mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
648 lines
24 KiB
C
648 lines
24 KiB
C
/* $Id: fb.c,v 1.5 2007/08/25 21:05:30 fredette Exp $ */
|
|
|
|
/* generic/fb.c - generic framebuffer implementation support: */
|
|
|
|
/*
|
|
* Copyright (c) 2003 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <tme/common.h>
|
|
_TME_RCSID("$Id: fb.c,v 1.5 2007/08/25 21:05:30 fredette Exp $");
|
|
|
|
/* includes: */
|
|
#include <tme/generic/fb.h>
|
|
|
|
/* include the automatically-generated translation functions: */
|
|
#include "fb-xlat-auto.c"
|
|
|
|
/* macros: */
|
|
#define TME_FB_COLORSET_DIRECT_COLOR (1)
|
|
#define TME_FB_COLORSET_PSEUDO_COLOR (2)
|
|
|
|
/* this returns the best translation function: */
|
|
const struct tme_fb_xlat *
|
|
tme_fb_xlat_best(const struct tme_fb_xlat *xlat_user)
|
|
{
|
|
unsigned int xlat_i;
|
|
const struct tme_fb_xlat *xlat;
|
|
const struct tme_fb_xlat *xlat_best;
|
|
unsigned int xlat_best_score, xlat_score;
|
|
|
|
/* loop over the xlats: */
|
|
xlat_best = NULL;
|
|
xlat_best_score = 0;
|
|
for (xlat_i = 0;
|
|
xlat_i < TME_ARRAY_ELS(tme_fb_xlats);
|
|
xlat_i++) {
|
|
|
|
/* get this xlat: */
|
|
xlat = &tme_fb_xlats[xlat_i];
|
|
xlat_score = 0;
|
|
|
|
/* if this xlat only works for a particular value of the given
|
|
member, and the user's value is different, we cannot use this
|
|
xlat. otherwise, increase this xlat's score: */
|
|
#define TME_FB_XLAT_SCORE(score, member, specific) \
|
|
if ((xlat->member specific) \
|
|
&& (xlat->member != xlat_user->member)) { \
|
|
continue; \
|
|
} \
|
|
if (xlat->member specific) \
|
|
xlat_score += score
|
|
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_width, != 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_height, != 0);
|
|
TME_FB_XLAT_SCORE( 0, tme_fb_xlat_scale, || TRUE);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_depth, != 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_bits_per_pixel, != 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_skipx, >= 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_scanline_pad, != 0);
|
|
TME_FB_XLAT_SCORE( 0, tme_fb_xlat_src_order, || TRUE);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_class, != TME_FB_XLAT_CLASS_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_map, != TME_FB_XLAT_MAP_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_map_bits, != 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_mask_g, != TME_FB_XLAT_MASK_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_mask_r, != TME_FB_XLAT_MASK_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_src_mask_b, != TME_FB_XLAT_MASK_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_depth, != 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_bits_per_pixel, != 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_skipx, >= 0);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_scanline_pad, != 0);
|
|
TME_FB_XLAT_SCORE( 0, tme_fb_xlat_dst_order, || TRUE);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_map, != TME_FB_XLAT_MAP_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_mask_g, != TME_FB_XLAT_MASK_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_mask_r, != TME_FB_XLAT_MASK_ANY);
|
|
TME_FB_XLAT_SCORE(100, tme_fb_xlat_dst_mask_b, != TME_FB_XLAT_MASK_ANY);
|
|
|
|
#undef TME_FB_XLAT_SCORE
|
|
|
|
/* update the best xlat: */
|
|
if (xlat_best == NULL
|
|
|| xlat_best_score < xlat_score) {
|
|
xlat_best = xlat;
|
|
xlat_best_score = xlat_score;
|
|
}
|
|
}
|
|
|
|
/* return the best xlat: */
|
|
assert (xlat_best != NULL);
|
|
return (xlat_best);
|
|
}
|
|
|
|
/* this returns nonzero iff the translation function is optimal: */
|
|
int
|
|
tme_fb_xlat_is_optimal(const struct tme_fb_xlat *xlat)
|
|
{
|
|
return (xlat->tme_fb_xlat_width != 0
|
|
&& xlat->tme_fb_xlat_height != 0
|
|
&& xlat->tme_fb_xlat_src_depth != 0
|
|
&& xlat->tme_fb_xlat_src_bits_per_pixel != 0
|
|
&& xlat->tme_fb_xlat_src_skipx >= 0
|
|
&& xlat->tme_fb_xlat_src_scanline_pad != 0
|
|
&& xlat->tme_fb_xlat_src_class != TME_FB_XLAT_CLASS_ANY
|
|
&& xlat->tme_fb_xlat_src_map != TME_FB_XLAT_MAP_ANY
|
|
&& xlat->tme_fb_xlat_src_map_bits != 0
|
|
&& xlat->tme_fb_xlat_src_mask_g != TME_FB_XLAT_MASK_ANY
|
|
&& xlat->tme_fb_xlat_src_mask_r != TME_FB_XLAT_MASK_ANY
|
|
&& xlat->tme_fb_xlat_src_mask_b != TME_FB_XLAT_MASK_ANY
|
|
&& xlat->tme_fb_xlat_dst_depth != 0
|
|
&& xlat->tme_fb_xlat_dst_bits_per_pixel != 0
|
|
&& xlat->tme_fb_xlat_dst_skipx >= 0
|
|
&& xlat->tme_fb_xlat_dst_scanline_pad != 0
|
|
&& xlat->tme_fb_xlat_dst_map != TME_FB_XLAT_MAP_ANY
|
|
&& xlat->tme_fb_xlat_dst_mask_g != TME_FB_XLAT_MASK_ANY
|
|
&& xlat->tme_fb_xlat_dst_mask_r != TME_FB_XLAT_MASK_ANY
|
|
&& xlat->tme_fb_xlat_dst_mask_b != TME_FB_XLAT_MASK_ANY
|
|
);
|
|
}
|
|
|
|
/* this returns the number of bytes required for a source framebuffer
|
|
scanline: */
|
|
static unsigned long
|
|
_tme_fb_xlat_src_bypl(const struct tme_fb_connection *src)
|
|
{
|
|
/* NB that this definition must match the one in the
|
|
automatically-generated xlat functions: */
|
|
const unsigned long src_bypl
|
|
= (((((src->tme_fb_connection_skipx
|
|
+ src->tme_fb_connection_width)
|
|
* src->tme_fb_connection_bits_per_pixel)
|
|
+ (src->tme_fb_connection_scanline_pad - 1))
|
|
& -src->tme_fb_connection_scanline_pad)
|
|
/ 8);
|
|
return (src_bypl);
|
|
}
|
|
|
|
/* this returns the number of bytes required for a source framebuffer: */
|
|
static unsigned long
|
|
_tme_fb_xlat_src_bypb_real(const struct tme_fb_connection *src)
|
|
{
|
|
/* NB that these definitions must match those in the
|
|
automatically-generated xlat functions: */
|
|
const unsigned long src_bypl
|
|
= _tme_fb_xlat_src_bypl(src);
|
|
const unsigned long src_bypb_real
|
|
= (((src->tme_fb_connection_height * src_bypl) + 3) & -4);
|
|
return (src_bypb_real);
|
|
}
|
|
|
|
/* this returns the number of bytes allocated for a source framebuffer.
|
|
this includes the guard regions that are needed to guarantee that
|
|
the translation function main loop terminates: */
|
|
static unsigned long
|
|
_tme_fb_xlat_src_bypb(const struct tme_fb_connection *src)
|
|
{
|
|
/* NB that this definition must match the one in the
|
|
automatically-generated xlat functions: */
|
|
const unsigned long src_bypl
|
|
= _tme_fb_xlat_src_bypl(src);
|
|
const unsigned long src_bypb_real
|
|
= _tme_fb_xlat_src_bypb_real(src);
|
|
const unsigned long src_bypb
|
|
= ((src_bypb_real + (src_bypl * 2)) & -4);
|
|
return (src_bypb);
|
|
}
|
|
|
|
/* this forces the next translation to retranslate the entire buffer: */
|
|
void
|
|
tme_fb_xlat_redraw(struct tme_fb_connection *src)
|
|
{
|
|
const tme_uint32_t *src_user;
|
|
tme_uint32_t *src_back;
|
|
unsigned int count32;
|
|
|
|
src_user
|
|
= ((const tme_uint32_t *)
|
|
src->tme_fb_connection_buffer);
|
|
src_back
|
|
= ((tme_uint32_t *)
|
|
(src->tme_fb_connection_buffer
|
|
+ _tme_fb_xlat_src_bypb(src)));
|
|
for (count32 = _tme_fb_xlat_src_bypb_real(src) / sizeof(tme_uint32_t);
|
|
count32-- > 0; ) {
|
|
*(src_back++) = ~(*(src_user++));
|
|
}
|
|
}
|
|
|
|
/* this allocates memory for a source framebuffer: */
|
|
int
|
|
tme_fb_xlat_alloc_src(struct tme_fb_connection *src)
|
|
{
|
|
|
|
/* allocate the buffer. remember, this is really two buffers - the
|
|
first half is the real, current framebuffer, and the second half
|
|
holds the last frame that was translated: */
|
|
src->tme_fb_connection_buffer
|
|
= tme_new0(tme_uint8_t,
|
|
_tme_fb_xlat_src_bypb(src) * 2);
|
|
|
|
/* force the next translation to do a complete redraw: */
|
|
tme_fb_xlat_redraw(src);
|
|
|
|
return (TME_OK);
|
|
}
|
|
|
|
/* this internal function gets or sets the needed colors on a
|
|
destination framebuffer connection that is using the common
|
|
translation functions: */
|
|
static tme_uint32_t
|
|
_tme_fb_xlat_colors_get_set(const struct tme_fb_connection *src,
|
|
unsigned int scale,
|
|
struct tme_fb_connection *dst,
|
|
struct tme_fb_color **_colors,
|
|
int get)
|
|
{
|
|
tme_uint32_t src_mask;
|
|
tme_uint32_t src_mask_g;
|
|
tme_uint32_t src_mask_r;
|
|
tme_uint32_t src_mask_b;
|
|
tme_uint32_t src_shift_g;
|
|
tme_uint32_t src_shift_r;
|
|
tme_uint32_t src_shift_b;
|
|
const void *src_map_g;
|
|
const void *src_map_r;
|
|
const void *src_map_b;
|
|
tme_uint32_t value_g;
|
|
tme_uint32_t value_r;
|
|
tme_uint32_t value_b;
|
|
tme_uint32_t src_max_g;
|
|
tme_uint32_t src_max_r;
|
|
tme_uint32_t src_max_b;
|
|
tme_uint32_t color_count;
|
|
tme_uint32_t color_i;
|
|
tme_uint32_t color_j;
|
|
int compress_colors;
|
|
unsigned int dst_depth_g;
|
|
unsigned int dst_depth_r;
|
|
unsigned int dst_depth_b;
|
|
struct tme_fb_color *colors;
|
|
tme_uint32_t *pixels;
|
|
tme_uint32_t invert_mask;
|
|
tme_uint32_t colorset;
|
|
|
|
/* get how to decompose source pixels into subfields. if source
|
|
pixels have no subfields, act as if all of the subfields are the
|
|
entire source pixel: */
|
|
src_mask = (0xffffffff >> (32 - src->tme_fb_connection_depth));
|
|
src_mask_g = src->tme_fb_connection_mask_g;
|
|
src_mask_r = src->tme_fb_connection_mask_r;
|
|
src_mask_b = src->tme_fb_connection_mask_b;
|
|
if (src_mask_g == 0) {
|
|
src_mask_g = src_mask;
|
|
src_mask_r = src_mask;
|
|
src_mask_b = src_mask;
|
|
}
|
|
|
|
/* if source intensities are index mapped, their common maximum is
|
|
the mask of the mapping size range in bits: */
|
|
src_map_g = src->tme_fb_connection_map_g;
|
|
src_map_r = src->tme_fb_connection_map_r;
|
|
src_map_b = src->tme_fb_connection_map_b;
|
|
if (src_map_g != NULL) {
|
|
src_max_g = (0xffffffff >> (32 - src->tme_fb_connection_map_bits));
|
|
src_max_r = src_max_g;
|
|
src_max_b = src_max_g;
|
|
}
|
|
|
|
/* otherwise, source intensities are linearly mapped, and each
|
|
primary's maximum intensity is the base mask of its subfield: */
|
|
else {
|
|
src_max_g = TME_FB_XLAT_MAP_BASE_MASK(src_mask_g);
|
|
src_max_r = TME_FB_XLAT_MAP_BASE_MASK(src_mask_r);
|
|
src_max_b = TME_FB_XLAT_MAP_BASE_MASK(src_mask_b);
|
|
}
|
|
|
|
/* the source intensity maximums must be greater than zero, and not
|
|
larger than 16 bits: */
|
|
assert (src_max_g > 0 && src_max_g <= 0xffff);
|
|
assert (src_max_r > 0 && src_max_r <= 0xffff);
|
|
assert (src_max_b > 0 && src_max_b <= 0xffff);
|
|
|
|
/* get any inversion mask: */
|
|
invert_mask = (src->tme_fb_connection_inverted ? 0xffff : 0);
|
|
|
|
/* if we're halving, the intensity maximums are four times what they
|
|
would be otherwise, because the intensities from four pixels are
|
|
added together: */
|
|
if (scale == TME_FB_XLAT_SCALE_HALF) {
|
|
src_max_g *= 4;
|
|
src_max_r *= 4;
|
|
src_max_b *= 4;
|
|
}
|
|
|
|
/* if we're not halving, and either the source pixel mask is less
|
|
than the maximum index mask or source pixels have no subfields,
|
|
we will index map source pixels directly to destination
|
|
pixels: */
|
|
if (scale != TME_FB_XLAT_SCALE_HALF
|
|
&& (src_mask <= TME_FB_XLAT_MAP_INDEX_MASK_MAX
|
|
|| src_mask_g == src_mask)) {
|
|
|
|
/* we will allocate as many colors as we have source pixels: */
|
|
color_count = src_mask + 1;
|
|
colorset = TME_FB_COLORSET_NONE;
|
|
}
|
|
|
|
/* otherwise, either we're halving, or source pixels are too big to
|
|
map directly and they have subfields. the translation code will
|
|
decompose pixels into intensities: */
|
|
|
|
/* if the source class is monochrome, we only have to deal with
|
|
the green primary: */
|
|
else if (src->tme_fb_connection_class == TME_FB_XLAT_CLASS_MONOCHROME) {
|
|
|
|
/* the translation function will index map green intensity values
|
|
directly into pixels. we may need to scale the intensities so
|
|
they can be indexed: */
|
|
for (; src_max_g > TME_FB_XLAT_MAP_INDEX_MASK_MAX; src_max_g >>= 1);
|
|
|
|
/* allocate colors for src_max_g intensities: */
|
|
color_count = src_max_g + 1;
|
|
colorset = TME_FB_COLORSET_NONE;
|
|
src_mask_g = TME_FB_XLAT_MAP_INDEX_MASK_MAX;
|
|
src_map_g = NULL;
|
|
src_mask_r = src_mask_g;
|
|
src_mask_b = src_mask_g;
|
|
src_map_r = src_map_g;
|
|
src_map_b = src_map_g;
|
|
src_max_r = src_max_g;
|
|
src_max_b = src_max_g;
|
|
}
|
|
|
|
/* otherwise, we have to deal with all three primaries: */
|
|
|
|
/* if the destination is color and has subfields: */
|
|
else if (dst->tme_fb_connection_class == TME_FB_XLAT_CLASS_COLOR
|
|
&& dst->tme_fb_connection_mask_g != 0) {
|
|
|
|
/* if the destination maps intensities linearly, we don't need to
|
|
allocate colors at all: */
|
|
if (dst->tme_fb_connection_map_g == NULL) {
|
|
|
|
/* however, we can't do this yet with a source framebuffer that
|
|
is inverted: */
|
|
if (src->tme_fb_connection_inverted) {
|
|
abort();
|
|
}
|
|
|
|
/* nothing to do */
|
|
*_colors = NULL;
|
|
dst->tme_fb_connection_map_pixel_count = 0;
|
|
return (TME_FB_COLORSET_NONE);
|
|
}
|
|
|
|
/* otherwise, the translation function will index map the
|
|
intensity values into subfield values. we may need to scale
|
|
the intensities so they can be indexed: */
|
|
for (; src_max_g > TME_FB_XLAT_MAP_INDEX_MASK_MAX; src_max_g >>= 1);
|
|
for (; src_max_r > TME_FB_XLAT_MAP_INDEX_MASK_MAX; src_max_r >>= 1);
|
|
for (; src_max_b > TME_FB_XLAT_MAP_INDEX_MASK_MAX; src_max_b >>= 1);
|
|
|
|
/* size the color array: */
|
|
color_count = src_max_g + 1 + src_max_r + 1 + src_max_b + 1;
|
|
colorset = TME_FB_COLORSET_DIRECT_COLOR;
|
|
|
|
/* if we're getting the needed colors: */
|
|
if (get) {
|
|
|
|
/* allocate the color array: */
|
|
colors = tme_new0(struct tme_fb_color, color_count);
|
|
|
|
/* make the colors to allocate from all of the different
|
|
primary intensities: */
|
|
color_i = 0;
|
|
#define _TME_FB_XLAT_INDEX_COLORS(value, max, primary) \
|
|
do { \
|
|
for (value = 0; value <= (max); value++, color_i++) { \
|
|
colors[color_i].primary = ((0xffff * value) / (max)) ^ invert_mask;\
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
_TME_FB_XLAT_INDEX_COLORS(value_g, src_max_g, tme_fb_color_value_g);
|
|
_TME_FB_XLAT_INDEX_COLORS(value_r, src_max_r, tme_fb_color_value_r);
|
|
_TME_FB_XLAT_INDEX_COLORS(value_b, src_max_b, tme_fb_color_value_b);
|
|
#undef _TME_FB_XLAT_INDEX_COLORS
|
|
|
|
/* return the needed colors: */
|
|
*_colors = colors;
|
|
dst->tme_fb_connection_map_pixel_count = color_count;
|
|
return (colorset);
|
|
}
|
|
|
|
/* set up the intensity index maps: */
|
|
colors = *_colors;
|
|
color_i = 0;
|
|
#define __TME_FB_XLAT_INDEX_SUBFIELDS(value, max, primary_mask, primary_shift, primary_map, type)\
|
|
do { \
|
|
dst->primary_map = tme_new(type, (max) + 1); \
|
|
for (value = 0; value <= (max); value++, color_i++) { \
|
|
((type *) dst->primary_map)[value] \
|
|
= ((colors[color_i].tme_fb_color_pixel \
|
|
& dst->primary_mask) \
|
|
>> primary_shift); \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
#define _TME_FB_XLAT_INDEX_SUBFIELDS(value, max, primary_mask, primary_shift, primary_map)\
|
|
do { \
|
|
for (primary_shift = 0; \
|
|
((dst->primary_mask >> primary_shift) & 1) == 0; \
|
|
primary_shift++); \
|
|
if (TME_FB_XLAT_MAP_BASE_MASK(dst->primary_mask) <= 0xff) { \
|
|
__TME_FB_XLAT_INDEX_SUBFIELDS(value, max, primary_mask, primary_shift, primary_map, tme_uint8_t);\
|
|
} \
|
|
else { \
|
|
__TME_FB_XLAT_INDEX_SUBFIELDS(value, max, primary_mask, primary_shift, primary_map, tme_uint16_t);\
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
_TME_FB_XLAT_INDEX_SUBFIELDS(value_g, src_max_g, tme_fb_connection_mask_g, src_shift_g, tme_fb_connection_map_g);
|
|
_TME_FB_XLAT_INDEX_SUBFIELDS(value_r, src_max_r, tme_fb_connection_mask_r, src_shift_r, tme_fb_connection_map_r);
|
|
_TME_FB_XLAT_INDEX_SUBFIELDS(value_b, src_max_b, tme_fb_connection_mask_b, src_shift_b, tme_fb_connection_map_b);
|
|
#undef _TME_FB_XLAT_INDEX_SUBFIELDS
|
|
#undef __TME_FB_XLAT_INDEX_SUBFIELDS
|
|
}
|
|
|
|
/* otherwise, the destination is either not color or it doesn't
|
|
have subfields. we need to allocate colors to map fake
|
|
source pixels: */
|
|
else {
|
|
src_mask_g = TME_FB_XLAT_MASK_DEFAULT_G;
|
|
src_mask_r = TME_FB_XLAT_MASK_DEFAULT_R;
|
|
src_mask_b = TME_FB_XLAT_MASK_DEFAULT_B;
|
|
src_map_g = NULL;
|
|
src_map_r = NULL;
|
|
src_map_b = NULL;
|
|
src_max_g = TME_FB_XLAT_MAP_BASE_MASK(src_mask_g);
|
|
src_max_r = TME_FB_XLAT_MAP_BASE_MASK(src_mask_r);
|
|
src_max_b = TME_FB_XLAT_MAP_BASE_MASK(src_mask_b);
|
|
color_count = (src_mask_g | src_mask_r | src_mask_b) + 1;
|
|
colorset = TME_FB_COLORSET_PSEUDO_COLOR;
|
|
}
|
|
|
|
/* if we get here, we're allocating colors from source pixel values
|
|
(or possibly fake source pixel values): */
|
|
|
|
/* if we're getting the needed colors: */
|
|
if (get) {
|
|
|
|
/* if the number of colors we need is clearly more than the
|
|
destination's depth can possibly handle, and the destination is
|
|
either monochrome or is color with no pixel subfields, asking
|
|
for this huge number of distinct colors will probably get us a
|
|
poorly representative subset.
|
|
|
|
in general, we can't help this. but in the specific case of
|
|
source pixels that directly map to intensity(s), we can remove
|
|
some of the less significant bits of the source pixel subfield
|
|
mask(s), so that we only ask to allocate as many distinct
|
|
colors as the destination's depth can handle: */
|
|
compress_colors
|
|
= ((color_count >> dst->tme_fb_connection_depth) > 0
|
|
&& (dst->tme_fb_connection_class == TME_FB_XLAT_CLASS_MONOCHROME
|
|
|| dst->tme_fb_connection_mask_g == 0)
|
|
&& src_map_g == NULL);
|
|
if (compress_colors) {
|
|
|
|
/* get the depth for each primary: */
|
|
if (src->tme_fb_connection_class == TME_FB_XLAT_CLASS_MONOCHROME) {
|
|
dst_depth_g = dst->tme_fb_connection_depth;
|
|
dst_depth_r = 0;
|
|
dst_depth_b = 0;
|
|
}
|
|
else {
|
|
dst_depth_r = dst->tme_fb_connection_depth;
|
|
dst_depth_g = (dst_depth_r + 2) / 3;
|
|
dst_depth_r -= dst_depth_g;
|
|
dst_depth_b = (dst_depth_r + 1) / 2;
|
|
dst_depth_r -= dst_depth_b;
|
|
}
|
|
|
|
/* remove some of the less significant bits in the subfield
|
|
masks and recalculate the source intensity maximums: */
|
|
#define _TME_FB_XLAT_LIMIT_MASK(src_mask_i, src_max_i, dst_depth_i) \
|
|
do { \
|
|
src_mask_i ^= (src_mask_i & (src_mask_i >> dst_depth_i)); \
|
|
src_max_i = (src_mask_i ? TME_FB_XLAT_MAP_BASE_MASK(src_mask_i) : 1); \
|
|
} while (/* CONSTCOND */ 0)
|
|
_TME_FB_XLAT_LIMIT_MASK(src_mask_g, src_max_g, dst_depth_g);
|
|
_TME_FB_XLAT_LIMIT_MASK(src_mask_r, src_max_r, dst_depth_r);
|
|
_TME_FB_XLAT_LIMIT_MASK(src_mask_b, src_max_b, dst_depth_b);
|
|
#undef _TME_FB_XLAT_LIMIT_MASK
|
|
}
|
|
|
|
/* make shift counts for the subfields and shift their trailing zeroes off: */
|
|
for (src_shift_g = 0; (src_mask_g & 1) == 0; src_shift_g++, src_mask_g >>= 1);
|
|
for (src_shift_r = 0; (src_mask_r & 1) == 0; src_shift_r++, src_mask_r >>= 1);
|
|
for (src_shift_b = 0; (src_mask_b & 1) == 0; src_shift_b++, src_mask_b >>= 1);
|
|
|
|
/* allocate the color array: */
|
|
colors = tme_new0(struct tme_fb_color, color_count);
|
|
|
|
/* loop over the source pixels: */
|
|
for (color_i = 0;
|
|
color_i < color_count;
|
|
color_i++) {
|
|
|
|
/* get the raw primary values: */
|
|
value_g = (color_i >> src_shift_g) & src_mask_g;
|
|
value_r = (color_i >> src_shift_r) & src_mask_r;
|
|
value_b = (color_i >> src_shift_b) & src_mask_b;
|
|
|
|
/* we give a distinct pixel value for each distinct color we ask
|
|
for, since we may ask for a lot of duplicates. this isn't
|
|
really a pixel value at all, anywhere - it only serves to
|
|
group duplicate colors together in the color array: */
|
|
if (compress_colors) {
|
|
color_j = value_g;
|
|
color_j = (color_j * (src_mask_r + 1)) + value_r;
|
|
color_j = (color_j * (src_mask_b + 1)) + value_b;
|
|
}
|
|
else {
|
|
color_j = color_i;
|
|
}
|
|
|
|
/* if the primaries are index mapped, turn the raw primary
|
|
values into intensities: */
|
|
if (src_map_g != NULL) {
|
|
|
|
/* if intensities are stored as 8 bits: */
|
|
if (src_max_g <= 0xff) {
|
|
value_g = ((const tme_uint8_t *) src_map_g)[value_g];
|
|
value_r = ((const tme_uint8_t *) src_map_r)[value_r];
|
|
value_b = ((const tme_uint8_t *) src_map_b)[value_b];
|
|
}
|
|
|
|
/* otherwise, intensities are stored as 16 bits: */
|
|
else {
|
|
value_g = ((const tme_uint16_t *) src_map_g)[value_g];
|
|
value_r = ((const tme_uint16_t *) src_map_r)[value_r];
|
|
value_b = ((const tme_uint16_t *) src_map_b)[value_b];
|
|
}
|
|
}
|
|
|
|
/* scale the intensities to 16 bits and possibly invert them: */
|
|
value_g = ((0xffff * value_g) / src_max_g) ^ invert_mask;
|
|
value_r = ((0xffff * value_r) / src_max_r) ^ invert_mask;
|
|
value_b = ((0xffff * value_b) / src_max_b) ^ invert_mask;
|
|
|
|
/* if the source class is monochrome, use only the green primary: */
|
|
if (src->tme_fb_connection_class == TME_FB_XLAT_CLASS_MONOCHROME) {
|
|
value_r = value_g;
|
|
value_b = value_g;
|
|
}
|
|
|
|
/* allocate this color: */
|
|
colors[color_i].tme_fb_color_pixel = color_j;
|
|
colors[color_i].tme_fb_color_value_g = value_g;
|
|
colors[color_i].tme_fb_color_value_r = value_r;
|
|
colors[color_i].tme_fb_color_value_b = value_b;
|
|
}
|
|
|
|
/* return the needed colors: */
|
|
*_colors = colors;
|
|
dst->tme_fb_connection_map_pixel_count = color_count;
|
|
return (colorset);
|
|
}
|
|
|
|
/* otherwise, take in the allocated colors: */
|
|
colors = *_colors;
|
|
pixels = tme_new(tme_uint32_t, color_count);
|
|
for (color_i = 0;
|
|
color_i < color_count;
|
|
color_i++) {
|
|
pixels[color_i] = colors[color_i].tme_fb_color_pixel;
|
|
}
|
|
dst->tme_fb_connection_map_pixel = pixels;
|
|
dst->tme_fb_connection_map_pixel_count = color_count;
|
|
tme_free(colors);
|
|
return (0);
|
|
}
|
|
|
|
/* this gets the needed colors on a destination framebuffer connection
|
|
that is using the common translation functions: */
|
|
tme_uint32_t
|
|
tme_fb_xlat_colors_get(const struct tme_fb_connection *src,
|
|
unsigned int scale,
|
|
struct tme_fb_connection *dst,
|
|
struct tme_fb_color **_colors)
|
|
{
|
|
return (_tme_fb_xlat_colors_get_set(src, scale, dst, _colors, TRUE));
|
|
}
|
|
|
|
/* this sets the needed colors on a destination framebuffer connection
|
|
that is using the common translation functions: */
|
|
void
|
|
tme_fb_xlat_colors_set(const struct tme_fb_connection *src,
|
|
unsigned int scale,
|
|
struct tme_fb_connection *dst,
|
|
struct tme_fb_color *colors)
|
|
{
|
|
_tme_fb_xlat_colors_get_set(src, scale, dst, &colors, FALSE);
|
|
}
|
|
|
|
/* this scores a framebuffer connection: */
|
|
int
|
|
tme_fb_connection_score(struct tme_connection *conn, unsigned int *_score)
|
|
{
|
|
struct tme_fb_connection *conn_fb;
|
|
struct tme_fb_connection *conn_fb_other;
|
|
|
|
/* both sides must be Ethernet connections: */
|
|
assert(conn->tme_connection_type == TME_CONNECTION_FRAMEBUFFER);
|
|
assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_FRAMEBUFFER);
|
|
|
|
/* one side must be a real display and the other side must be a
|
|
framebuffer emulator: */
|
|
conn_fb = (struct tme_fb_connection *) conn;
|
|
conn_fb_other = (struct tme_fb_connection *) conn->tme_connection_other;
|
|
*_score = ((conn_fb->tme_fb_connection_mode_change != NULL)
|
|
!= (conn_fb_other->tme_fb_connection_mode_change != NULL));
|
|
return (TME_OK);
|
|
}
|
|
|