executor/src/dcmaketables.c

560 lines
16 KiB
C

/* 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;
}
}