mirror of
https://github.com/ctm/executor.git
synced 2024-11-10 10:04:30 +00:00
560 lines
16 KiB
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;
|
|
}
|
|
}
|