/* Copyright 1995 by Abacus Research and * Development, Inc. All rights reserved. */ #if !defined (OMIT_RCSID_STRINGS) char ROMlib_rcsid_dcmaketables[] = "$Id: dcmaketables.c 63 2004-12-24 18:19:43Z ctm $"; #endif #include "rsys/common.h" #include "rsys/depthconv.h" #include "rsys/cquick.h" /* This file contains routines to construct lookup tables used for * depth conversion, and works hand in hand with dcconvert.c. The * model is that the appropriate lookup table creation routine is * called with a pointer to allocated table space, that routine fills * in the table space with private data, and returns a pointer to a * function pointer that knows how to use the created table to * efficiently depth convert a rectangle. * * So how do you know how much table space to allocate? Good * question. Each of the table creation routines returns by reference * the table size it needs for the parameters you specified. If you * pass in NULL for the allocated table space, the function will not * actually create the table. So you can say: * * unsigned size; * void *table; * * depthconv_make_ind_to_ind_table (NULL, 1, 8, &size, cspec_array); * table = malloc (size); * depthconv_make_ind_to_ind_table (table, 1, 8, NULL, cspec_array); * * You can also use the DEPTHCONV_MAX_TABLE_SIZE macro, which is * guaranteed to always be "big enough": * * static uint8 table[DEPTHCONV_MAX_TABLE_SIZE]; * * depthconv_make_ind_to_ind_table (table, 1, 8, &size, cspec_array); * * The disadvantage, of course, is potentially wasted space. * * There are five functions to handle different conversion types. * "ind" is short for "indirect", and refers to 1, 2, 4, or 8 bpp * pixels. "rgb" refers to 16 or 32 bpp pixels containing separate * red, green, and blue components. * * depthconv_make_raw_table * depthconv_make_ind_to_ind_table * depthconv_make_ind_to_rgb_table * depthconv_make_rgb_to_ind_table * depthconv_make_rgb_to_rgb_table * * `depthconv_make_raw_table' can be used for mapping indirect pixels * to raw values either 1, 2, 4, 8, 16, or 32 bits wide without * constructing a ColorSpec array. */ /* This is a table of the conversion funcs to use for various in:out ratios. */ static const depthconv_func_t ind_src_conversion_funcs[] = { depthconv_1_32, depthconv_1_16, depthconv_1_8, depthconv_1_4, depthconv_1_2, depthconv_1_1, depthconv_2_1, depthconv_4_1, depthconv_8_1, NULL, /* There is no generic 16->1 converter. */ NULL, /* There is no generic 32->1 converter. */ }; /* This is an array of the various alignments we require for different * conversion types. The desired alignment varies depending on the * algorithm used. */ const int depthconv_ind_src_table_alignment[] = { 32, /* 1 -> 32 */ 16, /* 1 -> 16 */ 8, /* 1 -> 8 */ 4, /* 1 -> 4 */ 8, /* 1 -> 2 */ 256, /* 1 -> 1 */ 2, /* 2 -> 1 */ 4, /* 4 -> 1 */ 8, /* 8 -> 1 */ 0, /* 16 -> 1, impossible case for indirect pixel src. */ 0, /* 32 -> 1, impossible case for indirect pixel src. */ }; /* Table sizes needed for various in:out bpp ratios. */ static const int ind_src_unaligned_table_size[] = { sizeof (depthconv_1_32_data_t), sizeof (depthconv_1_16_data_t), sizeof (depthconv_1_8_data_t), sizeof (depthconv_1_4_data_t), sizeof (depthconv_1_2_data_t), sizeof (depthconv_1_1_data_t), sizeof (depthconv_2_1_data_t), sizeof (depthconv_4_1_data_t), sizeof (depthconv_8_1_data_t), 0, /* 16->1, impossible case for indirect pixel src. */ 0, /* 32->1, impossible case for indirect pixel src. */ }; #define CONVERSION_FUNC(log2_in_bpp, log2_out_bpp) \ ind_src_conversion_funcs[(log2_in_bpp) - (log2_out_bpp) + 5] #define TABLE_SIZE(log2_in_bpp, log2_out_bpp) \ ((ind_src_unaligned_table_size[(log2_in_bpp) - (log2_out_bpp) + 5] \ + sizeof (uint32) /* First long specifies log2_in_bpp. */ \ + DEPTHCONV_TABLE_ALIGNMENT (log2_in_bpp, log2_out_bpp) - 1) \ & (DEPTHCONV_TABLE_ALIGNMENT (log2_in_bpp, log2_out_bpp) - 1)) /* This macro handles the cases where the pixel depth is increasing by * a factor of two. We need a special case here because the lookup table * we use for this algorithm is in a different format than for the other * nondecreasing modes. */ #define DEPTH_INCREASING_BY_FACTOR_OF_2(bpp1, bpp2) \ static void \ maketable_ ## bpp1 ## _ ## bpp2 (void *d, const uint32 *map) \ { \ int c; \ uint16 *dst; \ \ for (c = 0, dst = (uint16 *) d; c < 256; c++) \ { \ uint16 new; \ int r, l; \ \ /* Compute initial left shift count. */ \ l = 16 - bpp2; \ \ /* Loop over all input pixels and create the lookup table entry. */ \ for (new = 0, r = 8 - bpp1; r >= 0; r -= bpp1) \ { \ uint32 v = map[(c >> r) & ((1UL << bpp1) - 1)]; \ new |= (v & ((1UL << bpp2) - 1)) << l; \ if (l == 0) \ { \ dst[0] = dst[3] = CW (new); \ dst[1] = dst[2] = CWC (0); \ dst += 4; \ l = 16 - bpp2; \ new = 0; \ } \ else \ l -= bpp2; \ } \ } \ } DEPTH_INCREASING_BY_FACTOR_OF_2 (1, 2) DEPTH_INCREASING_BY_FACTOR_OF_2 (2, 4) DEPTH_INCREASING_BY_FACTOR_OF_2 (4, 8) DEPTH_INCREASING_BY_FACTOR_OF_2 (8, 16) /* This macro handles the cases where the pixel depth is not decreasing. */ #define DEPTH_NONDECREASING(bpp1, bpp2, new_type) \ static void \ maketable_ ## bpp1 ## _ ## bpp2 (void *d, const uint32 *map) \ { \ int c; \ new_type *dst; \ \ for (c = 0, dst = (new_type *) d; c < 256; c++) \ { \ new_type new; \ int r, l; \ \ /* Compute initial left shift count. */ \ l = (8 * sizeof new) - bpp2; \ \ /* Loop over all input pixels and create the lookup table entry. */ \ for (new = 0, r = 8 - bpp1; r >= 0; r -= bpp1) \ { \ uint32 v = map[(c >> r) & ((1UL << bpp1) - 1)]; \ new |= (v & (0xFFFFFFFFUL >> (32 - bpp2))) << l; \ if (l == 0) \ { \ *dst++ = Cx (new); \ l = (8 * sizeof new) - bpp2; \ new = 0; \ } \ else \ l -= bpp2; \ } \ } \ } DEPTH_NONDECREASING (1, 1, uint8) /* 1 -> 2 handled above by `DEPTH_INCREASING_BY_FACTOR_OF_2'. */ DEPTH_NONDECREASING (1, 4, uint32) DEPTH_NONDECREASING (1, 8, uint32) DEPTH_NONDECREASING (1, 16, uint32) DEPTH_NONDECREASING (1, 32, uint32) DEPTH_NONDECREASING (2, 2, uint8) /* 2 -> 4 handled above by `DEPTH_INCREASING_BY_FACTOR_OF_2'. */ DEPTH_NONDECREASING (2, 8, uint32) DEPTH_NONDECREASING (2, 16, uint32) DEPTH_NONDECREASING (2, 32, uint32) DEPTH_NONDECREASING (4, 4, uint8) /* 4 -> 8 handled above by `DEPTH_INCREASING_BY_FACTOR_OF_2'. */ DEPTH_NONDECREASING (4, 16, uint32) DEPTH_NONDECREASING (4, 32, uint32) DEPTH_NONDECREASING (8, 8, uint8) /* 8 -> 16 handled above by `DEPTH_INCREASING_BY_FACTOR_OF_2'. */ DEPTH_NONDECREASING (8, 32, uint32) #define DEPTH_DECREASING(bpp1, bpp2) \ static void \ maketable_ ## bpp1 ## _ ## bpp2 (void *d, const uint32 *map) \ { \ int c; \ uint8 *dst; \ \ for (c = 0, dst = (uint8 *) d; c < 256; c++) \ { \ long offset; \ int r, l; \ uint8 new; \ \ /* Loop over all input pixels and create the lookup table entry. */\ for (r = 8 - bpp1, l = (8 * bpp2 / bpp1) - bpp2, new = 0; \ r >= 0; \ r -= bpp1, l -= bpp2) \ { \ new |= ((map[(c >> r) & ((1UL << bpp1) - 1)] \ & ((1UL << bpp2) - 1)) \ << l); \ } \ \ for (offset = 256 * (bpp1 / bpp2 - 1); offset >= 0; offset -= 256) \ { \ dst[offset] = new; \ new <<= (8 * bpp2 / bpp1); \ } \ ++dst; \ } \ } DEPTH_DECREASING (2, 1) DEPTH_DECREASING (4, 1) DEPTH_DECREASING (4, 2) DEPTH_DECREASING (8, 1) DEPTH_DECREASING (8, 2) DEPTH_DECREASING (8, 4) typedef void (*maketable_func_t)(void *, const uint32 *); /* This is a table of the functions to create mapping tables * for all combinations of in->out bpp's where in <= 8. */ static const maketable_func_t ind_src_table_builders[4][6] = { { maketable_1_1, maketable_1_2, maketable_1_4, maketable_1_8, maketable_1_16, maketable_1_32 }, { maketable_2_1, maketable_2_2, maketable_2_4, maketable_2_8, maketable_2_16, maketable_2_32 }, { maketable_4_1, maketable_4_2, maketable_4_4, maketable_4_8, maketable_4_16, maketable_4_32 }, { maketable_8_1, maketable_8_2, maketable_8_4, maketable_8_8, maketable_8_16, maketable_8_32 }, }; /* Returns TRUE iff the specified mapping has no effect (i.e. maps 0 to 0, * 1 to 1, 2 to 2, etc. */ static inline boolean_t nop_map_p (const uint32 *map, int bpp) { int i; for (i = (1 << bpp) - 1; i >= 0; i--) if (map[i] != (uint32) i) return FALSE; return TRUE; } /* This creates a table to map incoming pixels to "raw" bit patterns. * Bit patterns > 8 bits wide will be byte swapped before they are * written out. */ depthconv_func_t depthconv_make_raw_table (void *table_space, unsigned in_bpp, unsigned out_bpp, uint32 *table_size, const uint32 *mapping) { int log2_in_bpp, log2_out_bpp; /* Default to requesting an empty table size. */ if (table_size) *table_size = 0; /* Sanity check the incoming bpp's. */ if (in_bpp > 32 || out_bpp > 32 || (in_bpp > 8 && (out_bpp <= 8 || mapping))) return NULL; /* Compute the log2 of those bpp's and make sure they are legitimate. */ log2_in_bpp = ROMlib_log2[in_bpp]; log2_out_bpp = ROMlib_log2[out_bpp]; if (log2_in_bpp < 0 || log2_out_bpp < 0) return NULL; /* Check for the no translation case. */ if (in_bpp == out_bpp && (mapping == NULL || nop_map_p (mapping, in_bpp))) { if (table_size) *table_size = sizeof (uint32); /* To hold log2_in_bpp. */ if (table_space) *(uint32 *)table_space = log2_in_bpp; return depthconv_copy; } /* Compute the actual table size we need. */ if (table_size) { *table_size = TABLE_SIZE (log2_in_bpp, log2_out_bpp); gui_assert (*table_size <= DEPTHCONV_MAX_TABLE_SIZE); } /* Fill in the conversion table if necessary. */ if (table_space) { void *dst; uint32 map_space[256]; /* Create a NOP mapping if they specify a NULL mapping. */ if (mapping == NULL) { int i; for (i = (1 << in_bpp) - 1; i >= 0; i--) map_space[i] = i; mapping = map_space; } /* Align the table and crank out the data. */ *(uint32 *)table_space = log2_in_bpp; dst = DEPTHCONV_ALIGN_TABLE (table_space, log2_in_bpp, log2_out_bpp); (ind_src_table_builders[log2_in_bpp][log2_out_bpp]) (dst, mapping); } return CONVERSION_FUNC (log2_in_bpp, log2_out_bpp); } /* This creates a table to map indirect pixels to indirect pixels. * If MAPPING is NULL, assumes identity mapping (useful for straight * depth conversion). */ depthconv_func_t depthconv_make_ind_to_ind_table (void *table_space, unsigned in_bpp, unsigned out_bpp, uint32 *table_size, const ColorSpec *mapping) { uint32 *raw_map; /* Verify bpp. */ if (in_bpp > 8 || out_bpp > 8) { if (table_size) *table_size = 0; return NULL; } /* Translate the mapping table to a raw table if it will be used. */ raw_map = NULL; if (table_space) { int i; if (mapping) { raw_map = (uint32 *) alloca (256 * sizeof raw_map[0]); for (i = (1 << in_bpp) - 1; i >= 0; i--) raw_map[i] = COLORSPEC_VALUE_LOW_BYTE (&mapping[i]); } } return depthconv_make_raw_table (table_space, in_bpp, out_bpp, table_size, raw_map); } /* This creates a table to map indirect pixels to RGB pixels. */ depthconv_func_t depthconv_make_ind_to_rgb_table (void *table_space, unsigned in_bpp, uint32 *table_size, const ColorSpec *mapping, const rgb_spec_t *dst_rgb_spec) { uint32 raw_map[256]; unsigned out_bpp; /* Verify bpp. */ out_bpp = dst_rgb_spec->bpp; if (in_bpp > 8 || (out_bpp != 16 && out_bpp != 32)) { if (table_size) *table_size = 0; return NULL; } /* Translate the mapping table to a raw table if it will be used. */ if (table_space) { int i; for (i = (1 << in_bpp) - 1; i >= 0; i--) { uint32 v; /* Assemble the new RGB value. */ v = (*dst_rgb_spec->rgbcolor_to_pixel)(dst_rgb_spec, &mapping[i].rgb, TRUE); /* Write out the value to the raw array. We byte swap here * to counteract the byte swap that will happen later when * the raw table is built. */ raw_map[i] = (out_bpp == 16) ? CW (v) : CL (v); } } return depthconv_make_raw_table (table_space, in_bpp, out_bpp, table_size, raw_map); } /* This creates a table to map RGB pixels to indirect pixels. */ depthconv_func_t depthconv_make_rgb_to_ind_table (void *table_space, unsigned out_bpp, uint32 *table_size, CTabHandle mapping, ITabHandle itab, const rgb_spec_t *src_rgb_spec) { if (table_size) *table_size = sizeof (depthconv_rgb_to_ind_data_t); if (table_space) { depthconv_rgb_to_ind_data_t *d; /* Grab a pointer to the struct itself. */ d = (depthconv_rgb_to_ind_data_t *) table_space; d->log2_in_bpp = ROMlib_log2[src_rgb_spec->bpp]; /* Fill in the src rgb_spec. */ d->src_rgb_spec = src_rgb_spec; /* Save away some other info for later. */ d->swapped_ctab = RM (mapping); d->swapped_itab = RM (itab); } /* Return the function that does the actual transfer. */ if (src_rgb_spec->bpp == 16) switch (out_bpp) { case 1: return depthconv_16_1; case 2: return depthconv_16_2; case 4: return depthconv_16_4; case 8: return depthconv_16_8; } else if (src_rgb_spec->bpp == 32) switch (out_bpp) { case 1: return depthconv_32_1; case 2: return depthconv_32_2; case 4: return depthconv_32_4; case 8: return depthconv_32_8; } /* Shouldn't get here. */ gui_abort (); #if !defined (LETGCCWAIL) return NULL; #endif } /* This creates a table to map RGB pixels to RGB pixels. */ depthconv_func_t depthconv_make_rgb_to_rgb_table (void *table_space, uint32 *table_size, const rgb_spec_t *src_rgb_spec, const rgb_spec_t *dst_rgb_spec) { /* If no conversion takes place, hand it off to the simpler converter. */ if (src_rgb_spec == dst_rgb_spec) return depthconv_make_raw_table (table_space, src_rgb_spec->bpp, dst_rgb_spec->bpp, table_size, NULL); /* Nope, the RGB specs differ. Create appropriate info here. */ if (table_size) *table_size = sizeof (depthconv_rgb_to_rgb_data_t); if (table_space) { depthconv_rgb_to_rgb_data_t *d; /* Grab a pointer to the struct itself. */ d = (depthconv_rgb_to_rgb_data_t *) table_space; d->log2_in_bpp = ROMlib_log2[src_rgb_spec->bpp]; /* Record src rgb spec. */ d->src_rgb_spec = src_rgb_spec; /* Record dst rgb spec. */ d->dst_rgb_spec = dst_rgb_spec; } /* Return the appropriate conversion function. */ if (src_rgb_spec->bpp == 16) { if (dst_rgb_spec->bpp == 16) return depthconv_16_16; else return depthconv_16_32; } else { if (dst_rgb_spec->bpp == 16) return depthconv_32_16; else return depthconv_32_32; } }