Page MenuHomePhabricator

Reducing memory consumption for png files with PNG_COLOR_TYPE_PALETTE color type
Open, WishlistPublic

Description

When evas png loader meets png files with color type PNG_COLOR_TYPE_PALETTE,
it expands the palette into rgb data right away and from that moment, the data is handled as normal 32bit data.
If the colormap data is expanded to rgba data at rendering time, we can reduce memory usage roughly by 3/4.

Here is a simple draft of such implementation

  1. add color type
typedef enum {
   ...
   EFL_GFX_COLORSPACE_PALETTE
} Efl_Gfx_Colorspace;
  1. in png head loader, save palette info
evas_image_load_file_head_png() {
   switch (color_type) {
      case PNG_COLOR_TYPE_PALETTE:
         png_get_PLTE(palette, &num_palette);
         prop->palette_size = *num_palette;
         prop->palette = (DATA32*)palette;
         break;
   }
}
  1. allocate surface: 8bits/pixel
_evas_common_rgba_image_surface_size() {
   switch (cspace) {
      case EVAS_COLORSPACE_PALETTE:
         siz = w * h * sizeof(DATA8);
         break;
   }
}
  1. expand colormap data into rgba at rendering time
SCALE_FUNC(RGBA_Image *src, RGBA_Image *dst) {
   DATA32 *real_src = malloc();
   for (i = 0; i < h; i++) {
      for (j = 0; j < w; i++) {
         *(tmpptr) = src->cache_entry->palette[ ];
      }
   }
  // copy real_src to dst here
  free(real_src);
}
eunue created this task.Mar 5 2018, 9:32 PM
eunue updated the task description. (Show Details)Mar 5 2018, 10:13 PM

the problem is you have to do a lot of funcs to make this happen. scale, copy, blend, blend with mask, with and without color multiply etc. etc. .. you end up having to do about i think 20-50 functions. then you multiply by each pixel format. so that then goes up to 40-100 funcs after this to maintain. making this maintainable is the key. currently it would not be.

raster added a comment.Mar 6 2018, 3:47 AM

have a look at all the src/lib/evas/common/evas_op_*.c and under evas_op_*/*.c ... see how many functions there are. this is actually a bit of a mess and we should be auto-generating this code IMHO. but we don't. but adding a new source format (paletted) will multiple these functions basically by 2x. so it doubles the mess. that is not a good idea. and it's not only here. the scale funcs also take shortcuts too to avoid some overhead.

so yes,. it saves memory. but it adds code overhead/complexity. there also needs to be extra code to choose the paletted src versions of funcs vs the argb32. to do this i think this whole things needs a bit of a clean up so it can handle more than one source format sensibly.

and then there's the added fun of now having multiple texture upload paths too. not just argb32 and alpha but now needing paletted textures as well. :) so this adds a lot of code to do, so to do it well means building infrastructure first to make the cost sensible.

cedric added a comment.Mar 6 2018, 4:53 PM

It might be doable in a more easy way with GL. You would upload two texture, one with the palette and one with the image. Along with a shader that fetch the pixels from the image and then get the real colors from the palette texture, it should be doable and give you this memory benefit with the GL case. This would be building on the infrastructure already in place for GRY8 and ETC1/2. From there you can add the format to EET and have this also improve edje use with GL.

As for the software path, like raster says it start to be a lot of work and difficult to maintain. Maybe if the benefit is worth it, it could be a good idea to start looking at code generation solution. So that instead of writing this tons of function they get mostly generated. Still, quite some work.

ProhtMeyhet triaged this task as Wishlist priority.
raster added a comment.Dec 6 2018, 6:39 AM

btw - with code generation it'd need to understand the idea of not just read 1 pixel, write 1, but possibly read 2, 4, 8 etc. and write 2, 4, 8 (that's not including scaling/map transforms that need to read many samples, merge somehow then write)