From: Nick Bowler Date: Thu, 12 Jan 2023 05:51:41 +0000 (-0500) Subject: Performance improvements for runtime icon generation. X-Git-Url: http://git.draconx.ca/gitweb/rrace.git/commitdiff_plain/2345a9dba343693668ece5abbba1fe58e0e18ed8 Performance improvements for runtime icon generation. As most of the rows for any given icon tile are the same as the previously-generated row, it is not necessary to recompute the colour values every single time. The code can be adjusted to re-use the previously-computed row instead. Since the generic code now works on bytes, we can also replace the open-coded loops in the row generation with a couple of memset calls, which should help modern compilers produce more efficient output. All this reduces the amount of computation done by the generic code substantially, to roughly a quarter of what it was previously. Also take the time to remove some unneeded complexity in the EWMH formatting implementation, which further helps a little bit on the code size front. --- diff --git a/src/ewmhicon.c b/src/ewmhicon.c index 319ed3a..7e69ec8 100644 --- a/src/ewmhicon.c +++ b/src/ewmhicon.c @@ -1,6 +1,6 @@ /* * _NET_WM_ICON helpers for slide puzzle game - * Copyright © 2022 Nick Bowler + * Copyright © 2022-2023 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,41 +32,6 @@ enum { ICON_16x16, ICON_24x24, ICON_32x32, ICON_48x48, ICON_MAX }; -/* - * Allocate storage for the EWMH _NET_WM_ICON array. The sizes array is - * populated with pointers to the beginning of each icon's pixel data. For - * example, sizes[ICON_24x24] points to the first pixel of the 24x24 image. - * - * The returned value can then be passed to XChangeProperty to set the icon, - * (use EWMH_ICON_NELEM for the number of elements) and must be freed by the - * caller. - */ -static void *ewmh_icon_alloc(unsigned long **sizes) -{ - unsigned long *buf; - - buf = calloc(sizeof *buf, EWMH_ICON_NELEM); - if (buf) { - sizes[ICON_16x16] = buf; - *sizes[ICON_16x16]++ = 16; - *sizes[ICON_16x16]++ = 16; - - sizes[ICON_24x24] = sizes[ICON_16x16] + 16*16; - *sizes[ICON_24x24]++ = 24; - *sizes[ICON_24x24]++ = 24; - - sizes[ICON_32x32] = sizes[ICON_24x24] + 24*24; - *sizes[ICON_32x32]++ = 32; - *sizes[ICON_32x32]++ = 32; - - sizes[ICON_48x48] = sizes[ICON_32x32] + 32*32; - *sizes[ICON_48x48]++ = 48; - *sizes[ICON_48x48]++ = 48; - } - - return buf; -} - static unsigned long scale16to8(unsigned x) { return x*0xfful / 0xffff; @@ -80,43 +45,51 @@ static unsigned long wm_pixel(const XColor *c) | scale16to8(c->blue); } -static void do_remap(void *icon, unsigned size, const XColor *map) +static void do_remap(void *icon, unsigned area, const XColor *map) { unsigned char *index = icon; unsigned long *argb = icon; - unsigned i, count = size*size; + unsigned i; - for (i = 0; i < count; i++) { - argb[count-i-1] = wm_pixel(map + index[count-i-1]); + area--; + for (i = 0; i <= area; i++) { + argb[area-i] = wm_pixel(map + index[area-i]); } } void *ewmh_icon_generate(const unsigned long *seq, const XColor *map) { - unsigned long *buf, *sizes[ICON_MAX]; - unsigned i, j; + static const unsigned char dims[ICON_MAX] = { 16, 24, 32, 48 }; + unsigned long *work, *ret; + unsigned i, j, fullsize, size; - buf = ewmh_icon_alloc(sizes); - if (!buf) + work = ret = malloc(sizeof *work * EWMH_ICON_NELEM); + if (!work) return NULL; - for (i = 0; i < 9; i++) { - unsigned x = i%3, y = i/3; + for (i = fullsize = 0; i < ICON_MAX; i++) { + work += fullsize; - icon_tile16((void *)sizes[ICON_16x16], seq[i], x, y); - icon_tile24((void *)sizes[ICON_24x24], seq[i], x, y); - icon_tile32((void *)sizes[ICON_32x32], seq[i], x, y); - icon_tile48((void *)sizes[ICON_48x48], seq[i], x, y); - } + size = dims[i]; + *work++ = size; + *work++ = size; + + for (j = 0; j < 9; j++) { + unsigned x = j%3, y = j/3; - for (i = 0; i < ICON_MAX; i++) { - /* Produces the sequence 16, 24, 32, 48 */ - unsigned size = 16 + (1u<> 8*COLOUR_PRIMARY) & 0xff) +#define dark(c) (((c) >> 8*COLOUR_DARK) & 0xff) +#define light(c) (((c) >> 8*COLOUR_LIGHT) & 0xff) + +static void format_row(unsigned char *row, unsigned long c, unsigned s, + unsigned y, unsigned w, unsigned h) +{ + memset(row, dark(c), w); + memset(row, primary(c), y+s < h ? w-s : 0); + memset(row, light(c), y >= s ? MIN(s, h-y) : w-y); +} + +static void format_row2(unsigned char *row, unsigned long c, unsigned s, + unsigned y, unsigned w, unsigned h, unsigned stride) { - unsigned x; - - for (x = 0; x < w; x++) { - row[x] = (c >> 8*COLOUR_PRIMARY) & 0xff; - if (x < s || y < s) - row[x] = (c >> 8*COLOUR_LIGHT) & 0xff; - if ((x+s >= w && x+y >= w) || (y+s >= h && x+y >= h)) - row[x] = (c >> 8*COLOUR_DARK) & 0xff; + row += stride*y; + if (y > s && y+s < h) { + if (stride) + memcpy(row, row-stride, w); + } else { + format_row(row, c, s, y, w, h); } } @@ -42,16 +54,15 @@ static void format_row(unsigned char *row, unsigned long c, */ void icon_tile16(unsigned char *icon, unsigned long c, int tile_x, int tile_y) { - int out_x, out_y, out_w, y; unsigned char row[6]; + unsigned y, w; - out_x = tile_x * 11 / 2; - out_y = tile_y * 11 / 2; - out_w = (5 + (tile_x == 1)) * sizeof row[0]; + icon += 16*(11u*tile_y / 2) + (11u*tile_x / 2); - for (y = 0+(tile_y == 0); y < 6-(tile_y == 2); y++) { - format_row(row, c, 1, y, 6, 6); - memcpy(&icon[16 * out_y++ + out_x], &row[tile_x == 0], out_w); + w = 5+(tile_x&1u); + for (y = !tile_y; y < 6-(tile_y==2); y++) { + format_row2(row, c, 1, y, 6, 6, 0); + memcpy(&icon[16*(y-!tile_y)], &row[!tile_x], w); } } @@ -60,13 +71,12 @@ void icon_tile16(unsigned char *icon, unsigned long c, int tile_x, int tile_y) */ void icon_tile24(unsigned char *icon, unsigned long c, int tile_x, int tile_y) { - int out_x, out_y, y; + unsigned y; - out_x = tile_x * 8; - out_y = tile_y * 8; + icon += 8*(24u*tile_y + tile_x); for (y = 0; y < 8; y++) { - format_row(&icon[24 * out_y++ + out_x], c, 1, y, 8, 8); + format_row2(icon, c, 1, y, 8, 8, 24); } } @@ -76,15 +86,14 @@ void icon_tile24(unsigned char *icon, unsigned long c, int tile_x, int tile_y) */ void icon_tile32(unsigned char *icon, unsigned long c, int tile_x, int tile_y) { - int out_x, out_y, out_w, out_h, y; + unsigned y, w, h; - out_x = 10*tile_x + (tile_x > 0); - out_y = 10*tile_y + (tile_y > 0); - out_w = 10 + (tile_x != 1); - out_h = 10 + (tile_y != 1); + icon += 32*(10u*tile_y + !!tile_y) + (10u*tile_x + !!tile_x); - for (y = 0; y < out_h; y++) { - format_row(&icon[32 * out_y++ + out_x], c, 1, y, out_w, out_h); + w = 10u + (tile_x != 1); + h = 10u + (tile_y != 1); + for (y = 0; y < h; y++) { + format_row2(icon, c, 1, y, w, h, 32); } } @@ -93,12 +102,11 @@ void icon_tile32(unsigned char *icon, unsigned long c, int tile_x, int tile_y) */ void icon_tile48(unsigned char *icon, unsigned long c, int tile_x, int tile_y) { - int out_x, out_y, y; + unsigned y; - out_x = tile_x * 16; - out_y = tile_y * 16; + icon += 16*(48u*tile_y + tile_x); for (y = 0; y < 16; y++) { - format_row(&icon[48 * out_y++ + out_x], c, 2, y, 16, 16); + format_row2(icon, c, 2, y, 16, 16, 48); } }