Name
Colours — formats and palette management
Synopsis
#include <cyg/io/framebuf.h> typedef struct cyg_fb { cyg_ucount16 fb_depth; cyg_ucount16 fb_format; cyg_uint32 fb_flags0; … } cyg_fb; extern const cyg_uint8 cyg_fb_palette_ega[16 * 3]; extern const cyg_uint8 cyg_fb_palette_vga[256 * 3]; #define CYG_FB_DEFAULT_PALETTE_BLACK 0x00 #define CYG_FB_DEFAULT_PALETTE_BLUE 0x01 #define CYG_FB_DEFAULT_PALETTE_GREEN 0x02 #define CYG_FB_DEFAULT_PALETTE_CYAN 0x03 #define CYG_FB_DEFAULT_PALETTE_RED 0x04 #define CYG_FB_DEFAULT_PALETTE_MAGENTA 0x05 #define CYG_FB_DEFAULT_PALETTE_BROWN 0x06 #define CYG_FB_DEFAULT_PALETTE_LIGHTGREY 0x07 #define CYG_FB_DEFAULT_PALETTE_LIGHTGRAY 0x07 #define CYG_FB_DEFAULT_PALETTE_DARKGREY 0x08 #define CYG_FB_DEFAULT_PALETTE_DARKGRAY 0x08 #define CYG_FB_DEFAULT_PALETTE_LIGHTBLUE 0x09 #define CYG_FB_DEFAULT_PALETTE_LIGHTGREEN 0x0A #define CYG_FB_DEFAULT_PALETTE_LIGHTCYAN 0x0B #define CYG_FB_DEFAULT_PALETTE_LIGHTRED 0x0C #define CYG_FB_DEFAULT_PALETTE_LIGHTMAGENTA 0x0D #define CYG_FB_DEFAULT_PALETTE_YELLOW 0x0E #define CYG_FB_DEFAULT_PALETTE_WHITE 0x0F
cyg_ucount16 CYG_FB_FORMAT(
framebuf
)
;
void cyg_fb_read_palette(
cyg_fb* fb, cyg_ucount32 first, cyg_ucount32 count, void* data)
;
void cyg_fb_write_palette(
cyg_fb* fb, cyg_ucount32 first, cyg_ucount32 count, const void* data, cyg_ucount16 when)
;
cyg_fb_colour cyg_fb_make_colour(
cyg_fb* fb, cyg_ucount8 r, cyg_ucount8 g, cyg_ucount8 b)
;
void cyg_fb_break_colour(
cyg_fb* fb, cyg_fb_colour colour, cyg_ucount8* r, cyg_ucount8* g, cyg_ucount8* b)
;
void CYG_FB_READ_PALETTE(
FRAMEBUF
, cyg_ucount32 first, cyg_ucount32 count, void* data)
;
void CYG_FB_WRITE_PALETTE(
FRAMEBUF
, cyg_ucount32 first, cyg_ucount32 count, const void* data, cyg_ucount16 when)
;
cyg_fb_colour CYG_FB_MAKE_COLOUR(
FRAMEBUF
, cyg_ucount8 r, cyg_ucount8 g, cyg_ucount8 b)
;
void CYG_FB_BREAK_COLOUR(
FRAMEBUF
, cyg_fb_colour colour, cyg_ucount8* r, cyg_ucount8* g, cyg_ucount8* b)
;
Description
Managing colours can be one of the most difficult aspects of writing
graphics code, especially if that code is intended to be portable to
many different platforms. Displays can vary from 1bpp monochrome, via
2bpp and 4bpp greyscale, through 4bpp and 8bpp paletted, and up to
16bpp and 32bpp true colour - and those are just the more common
scenarios. The various drawing
primitives like cyg_fb_write_pixel
work in
terms of cyg_fb_colour values, usually an unsigned
integer. Exactly how the hardware interprets a
cyg_fb_colour depends on the format.
Colour Formats
There are a number of ways of finding out how these values will be interpreted by the hardware:
-
The
CYG_FB_FLAGS0_TRUE_COLOUR
flag is set for all true colour displays. The format parameter can be examined for more details but this is not usually necessary. Instead code can usecyg_fb_make_colour
orCYG_FB_MAKE_COLOUR
to construct a cyg_fb_colour value from red, green and blue components. -
If the
CYG_FB_FLAGS0_WRITEABLE_PALETTE
flag is set then a cyg_fb_colour value is an index into a lookup table known as the palette, and this table contains red, green and blue components. The size of the palette is determined by the display depth, so 16 entries for a 4bpp display and 256 entries for an 8bpp display. Application code or a graphics library can install its own palette so can control exactly what colour each cyg_fb_colour value corresponds to. Alternatively there is support for installing a default palette. -
If
CYG_FB_FLAGS0_PALETTE
is set butCYG_FB_FLAGS0_WRITEABLE_PALETTE
is clear then the hardware uses a fixed palette. There is no easy way for portable software to handle this case. The palette can be read at run-time, allowing the application's desired colours to be mapped to whichever palette entry provides the best match. However normally it will be necessary to write code specifically for the fixed palette. - Otherwise the display is monochrome or greyscale, depending on the depth. There are still variations, for example on a monochrome display colour 0 can be either white or black.
As an alternative or to provide additional information, the exact
colour format is provided by the fb_format
field of the cyg_fb structure or by the
CYG_FB_FORMAT
macro. It can be one of the
following (more entries may be added in future):
-
CYG_FB_FORMAT_1BPP_MONO_0_BLACK
- simple 1bpp monochrome display, with 0 as black or the darker of the two colours, and 1 as white or the ligher colour.
-
CYG_FB_FORMAT_1BPP_MONO_0_WHITE
- simple 1bpp monochrome display, with 0 as white or the lighter of the two colours, and 1 as black or the darker colour.
-
CYG_FB_FORMAT_1BPP_PAL888
- a 1bpp display which cannot easily be described as monochrome. This is unusual and not readily supported by portable code. It can happen if the framebuffer normally runs at a higher depth, for example 4bpp or 8bpp paletted, but is run at only 1bpp to save memory. Hence only two of the palette entries are used, but can be set to arbitrary colours. The palette may be read-only or read-write.
-
CYG_FB_FORMAT_2BPP_GREYSCALE_0_BLACK
- a 2bpp display offering four shades of grey, with 0 as black or the darkest of the four shades, and 3 as white or the lightest.
-
CYG_FB_FORMAT_2BPP_GREYSCALE_0_WHITE
- a 2bpp display offering four shades of grey, with 0 as white or the lightest of the four shades, and 3 as black or the darkest.
-
CYG_FB_FORMAT_2BPP_PAL888
- a 2bpp display which cannot easily be described as greyscale, for example providing black, red, blue and white as the four colours. This is unusual and not readily supported by portable code. It can happen if the framebuffer normally runs at a higher depth, for example 4bpp or 8bpp paletted, but is run at only 2bpp to save memory. Hence only four of the palette entries are used, but can be set to arbitrary colours. The palette may be read-only or read-write.
-
CYG_FB_FORMAT_4BPP_GREYSCALE_0_BLACK
- a 4bpp display offering sixteen shades of grey, with 0 as black or the darkest of the 16 shades, and 15 as white or the lighest.
-
CYG_FB_FORMAT_4BPP_GREYSCALE_0_WHITE
- a 4bpp display offering sixteen shades of grey, with 0 as white or the lightest of the 16 shades, and 15 as black or the darkest.
-
CYG_FB_FORMAT_4BPP_PAL888
- a 4bpp paletted display, allowing for 16 different colours on screen at the same time. The palette may be read-only or read-write.
-
CYG_FB_FORMAT_8BPP_PAL888
- an 8bpp paletted display, allowing for 256 different colours on screen at the same time. The palette may be read-only or read-write.
-
CYG_FB_FORMAT_8BPP_TRUE_332
- an 8bpp true colour display, with three bits (eight levels) of red and green intensity and two bits (four levels) of blue intensity.
-
CYG_FB_FORMAT_16BPP_TRUE_565
- a 16bpp true colour display with 5 bits each for red and blue and 6 bits for green.
-
CYG_FB_FORMAT_16BPP_TRUE_555
- a 16bpp true colour display with five bits each for red, green and blue, and one unused bit.
-
CYG_FB_FORMAT_32BPP_TRUE_0888
- a 32bpp true colour display with eight bits each for red, green and blue and eight bits unused.
For the true colour formats the format does not define exactly which
bits in the pixel are used for which colour. Instead the
cyg_fb_make_colour
and cyg_fb_break_colour
functions or the
equivalent macros should be used to construct or decompose pixel
values.
Paletted Displays
Palettes are the common way of implementing low-end colour displays.
There are two variants. A read-only palette provides a fixed set of
colours and it is up to application code to use these colours
appropriately. A read-write palette allows the application to select
its own set of colours. Displays providing a read-write palette will
have the CYG_FB_FLAGS0_WRITEABLE_PALETTE
flag set
in addition to CYG_FB_FLAGS0_PALETTE
.
Even if application code can install its own palette, many
applications do not exploit this functionality and instead stick with
a default. There are two standard palettes: the 16-entry PC EGA for
4bpp displays; and the 256-entry PC VGA, a superset of the EGA one,
for 8bpp displays. This package provides the data for both, in the
form of arrays cyg_fb_palette_ega
and
cyg_fb_palette_vga
, and 16
#define
's such as
CYG_FB_DEFAULT_PALETTE_BLACK
for the EGA colours
and the first 16 VGA colours. By default device drivers for read-write
paletted displays will install the appropriate default palette, but
this can be suppressed using configuration option
CYGFUN_IO_FRAMEBUF_INSTALL_DEFAULT_PALETTE
. If a
custom palette will be used then installing the default palette
involves wasting 48 or 768 bytes of memory.
It should be emphasized that displays vary widely. A colour such
as CYG_FB_DEFAULT_PALETTE_YELLOW
may appear rather
differently on two different displays, although it should always be
recognizable as yellow. Developers may wish to fine-tune the palette
for specific hardware.
The current palette can be retrieved using
cyg_fb_read_palette
or
CYG_FB_READ_PALETTE
. The
first
and count
arguments control which palette entries should be retrieved. For
example, to retrieve just palette entry 12
first
should be set to 12 and
count
should be set to 1. To retrieve all 256
entries for an 8bpp display, first
should be
set to 0 and count
should be set to 256. The
data
argument should point at an array of
bytes, allowing three bytes for every entry. Byte 0 will contain the red
intensity for the first entry, byte 1 green and byte 2 blue.
For read-write palettes the palette can be updated using
cyg_fb_write_palette
or
CYG_FB_WRITE_PALETTE
. The
first
and count
arguments
are the same as for cyg_fb_read_palette
, and the
data
argument should point at a suitable byte
array packed in the same way. The when
argument
should be one of CYG_FB_UPDATE_NOW
or
CYG_FB_UPDATE_VERTICAL_RETRACE
. With some displays
updating the palette in the middle of an update may result in visual
noise, so synchronizing to the vertical retrace avoids this. However
not all device drivers will support this.
There is an assumption that palette entries use 8 bits for each of the red, green and blue colour intensities. This is not always the case, but the device drivers will perform appropriate adjustments. Some hardware may use only 6 bits per colour, and the device driver will ignore the bottom two bits of the supplied intensity values. Occasionally hardware may use more than 8 bits, in which case the supplied 8 bits are shifted left appropriately and zero-padded. Device drivers for such hardware may also provide device-specific routines to manipulate the palette in a non-portable fashion.
True Colour displays
True colour displays are often easier to manage than paletted displays. However this comes at the cost of extra memory. A 16bpp true colour display requires twice as much memory as an 8bpp paletted display, yet can offer only 32 or 64 levels of intensity for each colour as opposed to the 256 levels provided by a palette. It also requires twice as much video memory bandwidth to send all the pixel data to the display for every refresh, which may impact the performance of the rest of the system. A 32bpp true colour display offers the same colour intensities but requires four times the memory and four times the bandwidth.
Exactly how the colour bits are organized in
a cyg_fb_colour pixel value is not
defined by the colour format. Instead code should use the
cyg_fb_make_colour
or
CYG_FB_MAKE_COLOUR
primitives. These take 8-bit
intensity levels for red, green and blue, and return the corresponding
cyg_fb_colour. When using the macro interface the
arithmetic happens at compile-time, for example:
#define BLACK CYG_FB_MAKE_COLOUR(FRAMEBUF, 0, 0, 0) #define WHITE CYG_FB_MAKE_COLOUR(FRAMEBUF, 255, 255, 255) #define RED CYG_FB_MAKE_COLOUR(FRAMEBUF, 255, 0, 0) #define GREEN CYG_FB_MAKE_COLOUR(FRAMEBUF, 0, 255, 0) #define BLUE CYG_FB_MAKE_COLOUR(FRAMEBUF, 0, 0, 255) #define YELLOW CYG_FB_MAKE_COLOUR(FRAMEBUF, 255, 255, 80)
Displays vary widely so the numbers may need to be adjusted to give the exact desired colours.
For symmetry there are also cyg_fb_break_colour
and CYG_FB_BREAK_COLOUR
primitives. These take a
cyg_fb_colour value and decompose it into its red, green
and blue components.
2024-03-18 | Open Publication License |