mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
engine/loaders: Migrate alpha premultiplying to the engine side.
It's not efficient to handle alpha premultiplying in every loader. The backend engine should be responsible for it. Now, we can remove duplicate code.
This commit is contained in:
parent
9fb66973f0
commit
e9b12aa9f7
12 changed files with 61 additions and 62 deletions
|
@ -28,7 +28,7 @@
|
||||||
class GlRenderer : public RenderMethod
|
class GlRenderer : public RenderMethod
|
||||||
{
|
{
|
||||||
public:
|
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<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
|
RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
|
||||||
RenderData prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
RenderData prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
||||||
|
|
|
@ -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 rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id);
|
||||||
bool rasterClear(SwSurface* surface);
|
bool rasterClear(SwSurface* surface);
|
||||||
void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len);
|
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);
|
bool rasterConvertCS(Surface* surface, ColorSpace to);
|
||||||
|
|
||||||
#endif /* _TVG_SW_COMMON_H_ */
|
#endif /* _TVG_SW_COMMON_H_ */
|
||||||
|
|
|
@ -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
|
//OPTIMIZE_ME: +SIMD
|
||||||
for (uint32_t y = 0; y < surface->h; y++) {
|
for (uint32_t y = 0; y < surface->h; y++) {
|
||||||
auto buffer = surface->buffer + surface->stride * 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ static bool inline cRasterTranslucentRect(SwSurface* surface, const SwBBox& regi
|
||||||
|
|
||||||
static bool inline cRasterABGRtoARGB(Surface* surface)
|
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;
|
auto buffer = surface->buffer;
|
||||||
for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) {
|
for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) {
|
||||||
|
|
|
@ -278,7 +278,10 @@ struct SwImageTask : SwTask
|
||||||
auto clipRegion = bbox;
|
auto clipRegion = bbox;
|
||||||
|
|
||||||
//Convert colorspace if it's not aligned.
|
//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.data = source->buffer;
|
||||||
image.w = source->w;
|
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->w = w;
|
||||||
surface->h = h;
|
surface->h = h;
|
||||||
surface->cs = cs;
|
surface->cs = cs;
|
||||||
|
surface->premultiplied = true;
|
||||||
|
surface->owner = true;
|
||||||
|
|
||||||
vport.x = vport.y = 0;
|
vport.x = vport.y = 0;
|
||||||
vport.w = surface->w;
|
vport.w = surface->w;
|
||||||
|
|
|
@ -72,7 +72,7 @@ struct Picture::Impl
|
||||||
~Impl()
|
~Impl()
|
||||||
{
|
{
|
||||||
if (paint) delete(paint);
|
if (paint) delete(paint);
|
||||||
free(surface);
|
delete(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dispose(RenderMethod& renderer)
|
bool dispose(RenderMethod& renderer)
|
||||||
|
@ -275,13 +275,10 @@ struct Picture::Impl
|
||||||
|
|
||||||
dup->loader = loader;
|
dup->loader = loader;
|
||||||
if (surface) {
|
if (surface) {
|
||||||
dup->surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
dup->surface = new Surface;
|
||||||
*dup->surface = *surface;
|
*dup->surface = *surface;
|
||||||
//TODO: It needs a better design...
|
//TODO: A dupilcation is not a proxy... it needs copy of the pixel data?
|
||||||
//Backend engines might try to align the colorspace.
|
dup->surface->owner = false;
|
||||||
//Since it shares the bitmap, duplications should not touch the data.
|
|
||||||
//Only the owner could manage it.
|
|
||||||
dup->surface->cs = ColorSpace::Unsupported;
|
|
||||||
}
|
}
|
||||||
dup->w = w;
|
dup->w = w;
|
||||||
dup->h = h;
|
dup->h = h;
|
||||||
|
|
|
@ -46,11 +46,13 @@ enum ColorSpace
|
||||||
|
|
||||||
struct Surface
|
struct Surface
|
||||||
{
|
{
|
||||||
//TODO: Union for multiple types
|
|
||||||
uint32_t* buffer;
|
uint32_t* buffer;
|
||||||
uint32_t stride;
|
uint32_t stride;
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
ColorSpace cs;
|
ColorSpace cs;
|
||||||
|
|
||||||
|
bool premultiplied; //Alpha-premultiplied
|
||||||
|
bool owner; //Only owner could modify the buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Compositor
|
struct Compositor
|
||||||
|
|
|
@ -158,12 +158,15 @@ unique_ptr<Surface> JpgLoader::bitmap()
|
||||||
{
|
{
|
||||||
if (!image) return nullptr;
|
if (!image) return nullptr;
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(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->buffer = (uint32_t*)(image);
|
||||||
surface->stride = w;
|
surface->stride = w;
|
||||||
surface->w = w;
|
surface->w = w;
|
||||||
surface->h = h;
|
surface->h = h;
|
||||||
surface->cs = cs;
|
surface->cs = cs;
|
||||||
|
surface->premultiplied = true;
|
||||||
|
surface->owner = true;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,24 +27,6 @@
|
||||||
/* Internal Class Implementation */
|
/* 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 */
|
/* External Class Implementation */
|
||||||
|
@ -109,8 +91,6 @@ bool PngLoader::read()
|
||||||
}
|
}
|
||||||
content = reinterpret_cast<uint32_t*>(buffer);
|
content = reinterpret_cast<uint32_t*>(buffer);
|
||||||
|
|
||||||
_premultiply(reinterpret_cast<uint32_t*>(buffer), image->width, image->height);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,12 +104,15 @@ unique_ptr<Surface> PngLoader::bitmap()
|
||||||
{
|
{
|
||||||
if (!content) return nullptr;
|
if (!content) return nullptr;
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
//TODO: It's better to keep this surface instance in the loader side
|
||||||
|
auto surface = new Surface;
|
||||||
surface->buffer = content;
|
surface->buffer = content;
|
||||||
surface->stride = w;
|
surface->stride = w;
|
||||||
surface->w = w;
|
surface->w = w;
|
||||||
surface->h = h;
|
surface->h = h;
|
||||||
surface->cs = cs;
|
surface->cs = cs;
|
||||||
|
surface->owner = true;
|
||||||
|
surface->premultiplied = false;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,12 +118,15 @@ unique_ptr<Surface> JpgLoader::bitmap()
|
||||||
|
|
||||||
if (!image) return nullptr;
|
if (!image) return nullptr;
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
//TODO: It's better to keep this surface instance in the loader side
|
||||||
|
auto surface = new Surface;
|
||||||
surface->buffer = reinterpret_cast<uint32_t*>(image);
|
surface->buffer = reinterpret_cast<uint32_t*>(image);
|
||||||
surface->stride = static_cast<uint32_t>(w);
|
surface->stride = static_cast<uint32_t>(w);
|
||||||
surface->w = static_cast<uint32_t>(w);
|
surface->w = static_cast<uint32_t>(w);
|
||||||
surface->h = static_cast<uint32_t>(h);
|
surface->h = static_cast<uint32_t>(h);
|
||||||
surface->cs = cs;
|
surface->cs = cs;
|
||||||
|
surface->premultiplied = true;
|
||||||
|
surface->owner = true;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,26 +29,6 @@
|
||||||
/* Internal Class Implementation */
|
/* 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()
|
void PngLoader::clear()
|
||||||
{
|
{
|
||||||
lodepng_state_cleanup(&state);
|
lodepng_state_cleanup(&state);
|
||||||
|
@ -174,12 +154,15 @@ unique_ptr<Surface> PngLoader::bitmap()
|
||||||
{
|
{
|
||||||
this->done();
|
this->done();
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
//TODO: It's better to keep this surface instance in the loader side
|
||||||
|
auto surface = new Surface;
|
||||||
surface->buffer = reinterpret_cast<uint32_t*>(image);
|
surface->buffer = reinterpret_cast<uint32_t*>(image);
|
||||||
surface->stride = static_cast<uint32_t>(w);
|
surface->stride = static_cast<uint32_t>(w);
|
||||||
surface->w = static_cast<uint32_t>(w);
|
surface->w = static_cast<uint32_t>(w);
|
||||||
surface->h = static_cast<uint32_t>(h);
|
surface->h = static_cast<uint32_t>(h);
|
||||||
surface->cs = cs;
|
surface->cs = cs;
|
||||||
|
surface->premultiplied = false;
|
||||||
|
surface->owner = true;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
@ -195,6 +178,4 @@ void PngLoader::run(unsigned tid)
|
||||||
auto height = static_cast<unsigned>(h);
|
auto height = static_cast<unsigned>(h);
|
||||||
|
|
||||||
lodepng_decode(&image, &width, &height, &state, data, size);
|
lodepng_decode(&image, &width, &height, &state, data, size);
|
||||||
|
|
||||||
_premultiply((uint32_t*)(image), width, height);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,12 +80,15 @@ unique_ptr<Surface> RawLoader::bitmap()
|
||||||
{
|
{
|
||||||
if (!content) return nullptr;
|
if (!content) return nullptr;
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
//TODO: It's better to keep this surface instance in the loader side
|
||||||
|
auto surface = new Surface;
|
||||||
surface->buffer = content;
|
surface->buffer = content;
|
||||||
surface->stride = static_cast<uint32_t>(w);
|
surface->stride = static_cast<uint32_t>(w);
|
||||||
surface->w = static_cast<uint32_t>(w);
|
surface->w = static_cast<uint32_t>(w);
|
||||||
surface->h = static_cast<uint32_t>(h);
|
surface->h = static_cast<uint32_t>(h);
|
||||||
surface->cs = cs;
|
surface->cs = cs;
|
||||||
|
surface->premultiplied = true;
|
||||||
|
surface->owner = true;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue