Some texture loading optimizations

This commit is contained in:
Andrei Alexeyev 2020-05-09 13:04:54 +03:00
parent 54ca97587c
commit d9a84e083d
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
12 changed files with 74 additions and 53 deletions

View file

@ -9,8 +9,8 @@ resources_gfx_dir = join_paths(resources_pkg_main, 'gfx')
# 3. Profile-specific
preset_webp = [
# Leanify doesn't handle webp (yet?), so skip it.
'--no-leanify',
# Leanify doesn't handle webp (yet?), but it'll work on alphamaps (they are always png)
'--leanify',
'--format', 'webp',
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

View file

@ -1,7 +1,7 @@
# Autogenerated by the atlas packer, do not modify
source = res/gfx/atlas_portraits_0.webp
alphamap = res/gfx/atlas_portraits_0.alphamap.webp
alphamap = res/gfx/atlas_portraits_0.alphamap.png
# -- Pasted from the global override file --

View file

@ -85,7 +85,7 @@ def write_sprite_def(dst, texture, region, texture_dimensions, overrides=None):
update_text_file(dst, text)
def write_texture_def(dst, texture, texture_fmt, global_overrides=None, local_overrides=None, have_alphamap=False):
def write_texture_def(dst, texture, texture_fmt, global_overrides=None, local_overrides=None, alphamap_tex_fmt=None):
dst.parent.mkdir(exist_ok=True, parents=True)
text = (
@ -93,8 +93,8 @@ def write_texture_def(dst, texture, texture_fmt, global_overrides=None, local_ov
f'source = res/gfx/{texture}.{texture_fmt}\n'
)
if have_alphamap:
text += f'alphamap = res/gfx/{texture}.alphamap.{texture_fmt}\n'
if alphamap_tex_fmt is not None:
text += f'alphamap = res/gfx/{texture}.alphamap.{alphamap_tex_fmt}\n'
if global_overrides is not None:
text += f'\n# -- Pasted from the global override file --\n\n{global_overrides.strip()}\n'
@ -448,10 +448,17 @@ def gen_atlas(overrides, src, dst, binsize, atlasname, tex_format=texture_format
if alphamap_path:
if alphamap_composite_cmd is None:
alphamap_composite_cmd = base_composite_cmd.copy() + ['xc:white']
alphamap_composite_cmd = base_composite_cmd.copy() + [
'xc:white',
'-colorspace', 'Gray',
]
alphamap_composite_cmd += [
str(alphamap_path), '-geometry', '{:+}{:+}'.format(rect.x + border, rect.y + border), '-composite'
str(alphamap_path),
'-geometry', '{:+}{:+}'.format(rect.x + border, rect.y + border),
'-channel', 'R',
'-separate',
'-composite',
]
override_path = overrides / get_override_file_name(name)
@ -478,10 +485,10 @@ def gen_atlas(overrides, src, dst, binsize, atlasname, tex_format=texture_format
tex_format,
texture_global_overrides,
texture_local_overrides,
have_alphamap=alphamap_composite_cmd is not None
alphamap_tex_fmt=None if alphamap_composite_cmd is None else 'png'
)
def process(composite_cmd, dstfile):
def process(composite_cmd, dstfile, tex_format=tex_format):
subprocess.check_call(composite_cmd)
oldfmt = dstfile.suffix[1:].lower()
@ -514,7 +521,7 @@ def gen_atlas(overrides, src, dst, binsize, atlasname, tex_format=texture_format
if alphamap_composite_cmd is not None:
alphamap_composite_cmd += [str(dstfile_alphamap)]
futures.append(executor.submit(lambda: process(alphamap_composite_cmd, dstfile_alphamap)))
futures.append(executor.submit(lambda: process(alphamap_composite_cmd, dstfile_alphamap, tex_format='png')))
# Wait for subprocesses to complete.
wait_for_futures(futures)

View file

@ -357,14 +357,14 @@ static void* load_texture_begin(const char *path, uint flags) {
}
}
if(!pixmap_load_file(source, &ld.pixmap)) {
if(!pixmap_load_file(source, &ld.pixmap, override_format)) {
log_error("%s: couldn't load texture image", source);
free(source_allocated);
free(alphamap_allocated);
return NULL;
}
if(alphamap_allocated && !pixmap_load_file(alphamap_allocated, &ld.pixmap_alphamap)) {
if(alphamap_allocated && !pixmap_load_file(alphamap_allocated, &ld.pixmap_alphamap, PIXMAP_FORMAT_R8)) {
log_error("%s: couldn't load texture alphamap", alphamap_allocated);
free(source_allocated);
free(alphamap_allocated);

View file

@ -179,7 +179,7 @@ static struct conversion_def* find_conversion(uint depth_in, uint depth_out) {
log_fatal("Pixmap conversion for %upbc -> %upbc undefined, please add", depth_in, depth_out);
}
static void* default_pixel(uint depth) {
static void *default_pixel(uint depth) {
static uint8_t default_u8[] = { 0, 0, 0, UINT8_MAX };
static uint16_t default_u16[] = { 0, 0, 0, UINT16_MAX };
static uint32_t default_u32[] = { 0, 0, 0, UINT32_MAX };
@ -194,7 +194,7 @@ static void* default_pixel(uint depth) {
}
}
void* pixmap_alloc_buffer(PixmapFormat format, size_t width, size_t height) {
void *pixmap_alloc_buffer(PixmapFormat format, size_t width, size_t height) {
assert(width >= 1);
assert(height >= 1);
size_t pixel_size = PIXMAP_FORMAT_PIXEL_SIZE(format);
@ -202,11 +202,11 @@ void* pixmap_alloc_buffer(PixmapFormat format, size_t width, size_t height) {
return calloc(width * height, pixel_size);
}
void* pixmap_alloc_buffer_for_copy(const Pixmap *src) {
void *pixmap_alloc_buffer_for_copy(const Pixmap *src) {
return pixmap_alloc_buffer(src->format, src->width, src->height);
}
void* pixmap_alloc_buffer_for_conversion(const Pixmap *src, PixmapFormat format) {
void *pixmap_alloc_buffer_for_conversion(const Pixmap *src, PixmapFormat format) {
return pixmap_alloc_buffer(format, src->width, src->height);
}
@ -339,17 +339,13 @@ void pixmap_flip_to_origin_inplace(Pixmap *src, PixmapOrigin origin) {
src->origin = origin;
}
bool pixmap_load_stream_tga(SDL_RWops *stream, Pixmap *dst) {
return false;
}
static PixmapLoader *pixmap_loaders[] = {
&pixmap_loader_png,
&pixmap_loader_webp,
NULL,
};
static PixmapLoader* pixmap_loader_for_filename(const char *file) {
static PixmapLoader *pixmap_loader_for_filename(const char *file) {
char *ext = strrchr(file, '.');
if(!ext || !*(++ext)) {
@ -368,13 +364,13 @@ static PixmapLoader* pixmap_loader_for_filename(const char *file) {
return NULL;
}
bool pixmap_load_stream(SDL_RWops *stream, Pixmap *dst) {
bool pixmap_load_stream(SDL_RWops *stream, Pixmap *dst, PixmapFormat preferred_format) {
for(PixmapLoader **loader = pixmap_loaders; *loader; ++loader) {
bool match = (*loader)->probe(stream);
SDL_RWseek(stream, 0, RW_SEEK_SET);
if(match) {
return (*loader)->load(stream, dst);
return (*loader)->load(stream, dst, preferred_format);
}
}
@ -382,7 +378,8 @@ bool pixmap_load_stream(SDL_RWops *stream, Pixmap *dst) {
return false;
}
bool pixmap_load_file(const char *path, Pixmap *dst) {
bool pixmap_load_file(const char *path, Pixmap *dst, PixmapFormat preferred_format) {
log_debug("%s %x", path, preferred_format);
SDL_RWops *stream = vfs_open(path, VFS_MODE_READ | VFS_MODE_SEEKABLE);
if(!stream) {
@ -390,7 +387,7 @@ bool pixmap_load_file(const char *path, Pixmap *dst) {
return false;
}
bool result = pixmap_load_stream(stream, dst);
bool result = pixmap_load_stream(stream, dst, preferred_format);
SDL_RWclose(stream);
return result;
}
@ -399,7 +396,7 @@ bool pixmap_check_filename(const char *path) {
return (bool)pixmap_loader_for_filename(path);
}
char* pixmap_source_path(const char *prefix, const char *path) {
char *pixmap_source_path(const char *prefix, const char *path) {
char base_path[strlen(prefix) + strlen(path) + 1];
strcpy(base_path, prefix);
strcpy(base_path + strlen(prefix), path);

View file

@ -150,9 +150,9 @@ typedef struct Pixmap {
PixmapOrigin origin;
} Pixmap;
void* pixmap_alloc_buffer(PixmapFormat format, size_t width, size_t height) attr_returns_allocated;
void* pixmap_alloc_buffer_for_copy(const Pixmap *src) attr_nonnull(1) attr_returns_allocated;
void* pixmap_alloc_buffer_for_conversion(const Pixmap *src, PixmapFormat format) attr_nonnull(1) attr_returns_allocated;
void *pixmap_alloc_buffer(PixmapFormat format, size_t width, size_t height) attr_returns_allocated;
void *pixmap_alloc_buffer_for_copy(const Pixmap *src) attr_nonnull(1) attr_returns_allocated;
void *pixmap_alloc_buffer_for_conversion(const Pixmap *src, PixmapFormat format) attr_nonnull(1) attr_returns_allocated;
void pixmap_copy(const Pixmap *src, Pixmap *dst) attr_nonnull(1, 2);
void pixmap_copy_alloc(const Pixmap *src, Pixmap *dst) attr_nonnull(1, 2);
@ -171,11 +171,10 @@ void pixmap_flip_to_origin_inplace(Pixmap *src, PixmapOrigin origin) attr_nonnul
size_t pixmap_data_size(const Pixmap *px) attr_nonnull(1);
bool pixmap_load_file(const char *path, Pixmap *dst) attr_nonnull(1, 2) attr_nodiscard;
bool pixmap_load_stream(SDL_RWops *stream, Pixmap *dst) attr_nonnull(1, 2) attr_nodiscard;
bool pixmap_load_stream_tga(SDL_RWops *stream, Pixmap *dst) attr_nonnull(1, 2) attr_nodiscard;
bool pixmap_load_file(const char *path, Pixmap *dst, PixmapFormat preferred_format) attr_nonnull(1, 2) attr_nodiscard;
bool pixmap_load_stream(SDL_RWops *stream, Pixmap *dst, PixmapFormat preferred_format) attr_nonnull(1, 2) attr_nodiscard;
bool pixmap_check_filename(const char *path);
char* pixmap_source_path(const char *prefix, const char *path) attr_nodiscard;
char *pixmap_source_path(const char *prefix, const char *path) attr_nodiscard;
#endif // IGUARD_util_pixmap_h

View file

@ -27,7 +27,9 @@ static void _CONV_FUNCNAME(
}
} else if(_CONV_OUT_IS_FLOAT) {
fill = *buf_in++ * (1.0f / (float)_CONV_IN_MAX);
} else if(_CONV_OUT_MAX >= _CONV_IN_MAX) {
} else if(_CONV_OUT_MAX == _CONV_IN_MAX) {
fill = *buf_in++;
} else if(_CONV_OUT_MAX > _CONV_IN_MAX) {
fill = *buf_in++ * (_CONV_OUT_MAX / _CONV_IN_MAX);
} else {
// TODO use fixed point math

View file

@ -20,7 +20,17 @@ static bool px_png_probe(SDL_RWops *stream) {
return !memcmp(magic, png_magic, sizeof(magic));
}
static bool px_png_load(SDL_RWops *stream, Pixmap *pixmap) {
static inline PixmapLayout clrtype_to_layout(png_byte color_type) {
switch(color_type) {
case PNG_COLOR_TYPE_RGB: return PIXMAP_LAYOUT_RGB;
case PNG_COLOR_TYPE_RGB_ALPHA: return PIXMAP_LAYOUT_RGBA;
case PNG_COLOR_TYPE_GRAY: return PIXMAP_LAYOUT_R;
}
UNREACHABLE;
}
static bool px_png_load(SDL_RWops *stream, Pixmap *pixmap, PixmapFormat preferred_format) {
png_structp png = NULL;
png_infop png_info = NULL;
const char *volatile error = NULL;
@ -50,23 +60,26 @@ static bool px_png_load(SDL_RWops *stream, Pixmap *pixmap) {
png_set_alpha_mode(png, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
if(color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png);
}
/*
* Expand palette into RGB
* Expand grayscale to full 8 bits
* Expand transparency to full RGBA
*/
png_set_expand(png);
if(png_get_valid(png, png_info, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png);
}
// avoid unnecessary back-and-forth conversion
bool keep_gray = (
color_type == PNG_COLOR_TYPE_GRAY &&
PIXMAP_FORMAT_LAYOUT(preferred_format) == PIXMAP_LAYOUT_R
);
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
png_set_expand_gray_1_2_4_to_8(png);
}
if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
if(!keep_gray) {
png_set_gray_to_rgb(png);
}
png_set_expand(png);
if(PIXMAP_FORMAT_DEPTH(preferred_format) == 16) {
png_set_expand_16(png);
}
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
png_set_swap(png);
@ -79,14 +92,17 @@ static bool px_png_load(SDL_RWops *stream, Pixmap *pixmap) {
color_type = png_get_color_type(png, png_info);
bit_depth = png_get_bit_depth(png, png_info);
assert(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGBA);
assert(
(color_type == PNG_COLOR_TYPE_RGB && channels == 3) ||
(color_type == PNG_COLOR_TYPE_RGB_ALPHA && channels == 4) ||
(color_type == PNG_COLOR_TYPE_GRAY && channels == 1)
);
assert(bit_depth == 8 || bit_depth == 16);
assert(channels == 3 || channels == 4);
pixmap->width = png_get_image_width(png, png_info);
pixmap->height = png_get_image_height(png, png_info);
pixmap->format = PIXMAP_MAKE_FORMAT(
channels == 3 ? PIXMAP_LAYOUT_RGB : PIXMAP_LAYOUT_RGBA,
clrtype_to_layout(color_type),
bit_depth
);

View file

@ -49,7 +49,7 @@ static inline const char* webp_error_str(VP8StatusCode code) {
return "Unknown error";
}
static bool px_webp_load(SDL_RWops *stream, Pixmap *pixmap) {
static bool px_webp_load(SDL_RWops *stream, Pixmap *pixmap, PixmapFormat preferred_format) {
WebPDecoderConfig config;
int status = WebPInitDecoderConfig(&config);

View file

@ -17,7 +17,7 @@
typedef struct PixmapLoader {
bool (*probe)(SDL_RWops *stream);
bool (*load)(SDL_RWops *stream, Pixmap *pixmap);
bool (*load)(SDL_RWops *stream, Pixmap *pixmap, PixmapFormat preferred_format);
const char **filename_exts;
} PixmapLoader;