When developing an application for a specific platform the various
framebuffer parameters such as width and height are known, and the
code can be written accordingly. However when writing code that should
work on many platforms with different framebuffer devices, for example
a graphics library, the code must be able to get these parameters and
adapt.
Code using the function API can extract the parameters from the
cyg_fb structures at run-time. The macro API
provides dedicated macros for each parameter. These do not follow the
usual eCos convention where the result is provided via an extra
argument. Instead the result is returned as normal, and is guaranteed
to be a compile-time constant. This allows code like the following:
#if CYG_FB_DEPTH(FRAMEBUF) < 8
…
#else
…
#endif
or alternatively:
if (CYG_FB_DEPTH(FRAMEBUF) < 8) {
…
} else {
…
}
or:
switch (CYG_FB_DEPTH(FRAMEBUF)) {
case 1 : … break;
case 2 : … break;
case 4 : … break;
case 8 : … break;
case 16 : … break;
case 32 : … break;
}
In terms of the code actually generated by the compiler these
approaches have much the same effect. The macros expand to a
compile-time constant so unnecessary code can be easily eliminated.
The available parameters are as follows:
depth
The number of bits per pixel or bpp. The common depths are 1, 2, 4, 8,
16 and 32.
format
How the pixel values are mapped on to visible colours, for example true colour
or paletted or greyscale.
width, height
The number of framebuffer pixels horizontally and vertically.
viewport width, viewport height
With some devices the framebuffer height and/or width are greater than
what the display can actually show. The display is said to offer a
viewport into the larger framebuffer. The number of visible pixels is
determined from the viewport width and height. The position of the
viewport is controlled via an ioctl.
Within a cyg_fb structure these fields are
only present if
CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_VIEWPORT
is defined, to avoid wasting data space on fields that are unnecessary
for the current platform. For the macro API the viewport macros should only be used
if CYG_FB_FLAGS0_VIEWPORT is set for the framebuffer:
For linear
framebuffers these parameters provide the information needed to access
framebuffer memory. The stride is in bytes.
flags0
This gives further information about the hardware capabilities.
Some of this overlaps with other parameters, especially when it comes
to colour, because it is often easier to test for a single flag than
for a range of colour modes. The current flags are:
CYG_FB_FLAGS0_LINEAR_FRAMEBUFFER
Framebuffer memory is organized in a conventional fashion and can be
accessed directly by
higher-level code using the base and stride parameters.
CYG_FB_FLAGS0_LE
This flag is only relevant for 1bpp, 2bpp and 4bpp devices and
controls how the pixels are organized within each byte. If the flag is
set then the layout is little-endian: for a 1bpp device pixel (0,0)
occupies bit 0 of the first byte of framebuffer memory. The more
common layout is big-endian where pixel (0,0) occupies bit 7 of the
first byte.
CYG_FB_FLAGS0_TRUE_COLOUR
The framebuffer uses a true colour format where the value of each
pixel directly encodes the red, green and blue intensities. This is
common for 16bpp and 32bpp devices, and is occasionally used for 8bpp
devices.
CYG_FB_FLAGS0_PALETTE
The framebuffer uses a palette. A pixel value does not directly encode
the colours, but instead acts as an index into a separate table of
colour values. That table may be read-only or read-write. Paletted
displays are common for 8bpp and some 4bpp displays.
CYG_FB_FLAGS0_WRITEABLE_PALETTE
The palette is read-write.
CYG_FB_FLAGS0_DELAYED_PALETTE_UPDATE
Palette updates can be synchronized to a vertical blank, in other
words a brief time period when the display is not being updated,
by using CYG_FB_UPDATE_VERTICAL_RETRACE as the last
argument to cyg_fb_write_palette or
CYG_FB_WRITE_PALETTE. With some hardware updating
the palette in the middle of a screen update may result in visual noise.
CYG_FB_FLAGS0_VIEWPORT
The framebuffer contains more pixels than can be shown on the display.
Instead the display provides a viewport into the framebuffer. An
ioctl
can be used to move the viewport.
CYG_FB_FLAGS0_DOUBLE_BUFFER
The display does not show the current contents of the framebuffer, so
the results of drawing into the framebuffer are not immediately
visible. Instead higher-level code needs to perform an explicit
synch operation to
update the display.
CYG_FB_FLAGS0_PAGE_FLIPPING
The hardware supports two or more pages, each of width*height pixels,
only one of which is visible on the display. This allows higher-level
code to update one page without disturbing what is currently visible.
An ioctl
is used to switch the visible page.
CYG_FB_FLAGS0_BLANK
The display can be blanked
without affecting the framebuffer contents or settings.
CYG_FB_FLAGS0_BACKLIGHT
There is a backlight which can be switched
on or off. Some hardware provides finer-grained control over the
backlight intensity.
CYG_FB_FLAGS0_MUST_BE_ON
Often it is desirable to perform some initialization such as clearing
the screen or setting the palette before the display is switched on, to avoid visual
noise. However not all hardware allows this. If this flag is set then
it is possible to access framebuffer memory and the palette before the
cyg_fb_on or CYG_FB_ON
operation. It may also be possible to perform some other operations
such as activating the backlight, but that is implementation-defined.
To allow for future expansion there are also flags1, flags2, and
flags3 fields. These may get used for encoding additional
ioctl functionality, support for hardware
acceleration, and similar features.
Linear Framebuffers
There are drawing primitives for writing and reading individual
pixels. However these involve a certain amount of arithmetic each time
to get from a position to an address within the frame buffer, plus
function call overhead if the function API is used, and this will slow
down graphics operations.
When the framebuffer device is known at compile-time and the macro API
is used then there are additional macros specifically for iterating over parts of the frame
buffer. These should prove very efficient for many graphics
operations. However if the device is selected at run-time then the
macros are not appropriate and code may want to manipulate framebuffer
memory directly. This is possible if two conditions are satisfied:
The CYG_FB_FLAGS0_LINEAR_FRAMEBUFFER flag must be
set. Otherwise framebuffer memory is either not directly accessible or
has a non-linear layout.
The CYG_FB_FLAGS0_DOUBLE_BUFFER flag must be clear.
An efficient double buffer synch operation requires knowing what part
of the framebuffer have been updated, and the various drawing
primitives will keep track of this. If higher-level code then starts
manipulating the framebuffer directly the synch operation may perform
only a partial update.
The base, stride, depth, width and height parameters, plus the
CYG_FB_FLAGS0_LE flag for 1bpp, 2bpp and 4bpp
devices, provide all the information needed to access framebuffer
memory. A linear framebuffer has pixel (0,0) at the base address.
Incrementing y means adding stride bytes to the pointer.
The base and stride parameters may be set even if
CYG_FB_FLAGS0_LINEAR_FRAMEBUFFER is clear. This can
be useful if for example the display is rotated in software from
landscape to portrait mode. However the meaning of these parameters
for non-linear framebuffers is implementation-defined.