[RFC] Standardize YUV support in the fbdev API
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Tue May 17 15:07:20 PDT 2011
Hi everybody,
I need to implement support for a YUV frame buffer in an fbdev driver. As the
fbdev API doesn't support this out of the box, I've spent a couple of days
reading fbdev (and KMS) code and thinking about how we could cleanly add YUV
support to the API. I'd like to share my findings and thoughts, and hopefully
receive some comments back.
The terms 'format', 'pixel format', 'frame buffer format' and 'data format'
will be used interchangeably in this e-mail. They all refer to the way pixels
are stored in memory, including both the representation of a pixel as integer
values and the layout of those integer values in memory.
History and current situation
-----------------------------
The fbdev API predates YUV frame buffers. In those old days developers only
cared (and probably thought) about RGB frame buffers, and they developed an
API that could express all kind of weird RGB layout in memory (such as R-
GGGGGGGGGGG-BBBB for instance, I can't imagine hardware implementing that).
This resulted in individual bit field description for the red, green, blue and
alpha components:
struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */
};
Grayscale formats were pretty common, so a grayscale field tells color formats
(grayscale == 0) from grayscale formats (grayscale != 0).
People already realized that hardware developers were crazily inventive (the
word to remember here is crazily), and that non-standard formats would be
needed at some point. The fb_var_screeninfo ended up containing the following
format-related fields.
struct fb_var_screeninfo {
...
__u32 bits_per_pixel; /* guess what */
__u32 grayscale; /* != 0 Graylevels instead of colors */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
__u32 nonstd; /* != 0 Non standard pixel format */
...
};
Two bits have been specified for the nonstd field:
#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */
#define FB_NONSTD_REV_PIX_IN_B 2 /* order of pixels in each byte is reversed
*/
The FB_NONSTD_HAM bit is used by the video/amifb.c driver only to enable HAM
mode[1]. I very much doubt that any new hardware will implement HAM mode (and
I certainly hope none will).
The FB_NONSTD_REV_PIX_IN_B is used in video/fb_draw.h by the generic bitblit,
fillrect and copy area implementations, not directly by drivers.
A couple of drivers hardcode the nonstd field to 1 for some reason. Those are
video/arcfb.c (1bpp gray display), video/hecubafb.c (1bpp gray display) and
video/metronomefb.c (8bpp gray display).
The following drivers use nonstd for various other (and sometimes weird)
purposes:
video/arkfb.c
Used in 4bpp mode only, to control fb_setcolreg operation
video/fsl-diu-fb.c
Set var->nonstd bits into var->sync (why?)
video/pxafb.c
Encode frame buffer xpos and ypos in the nonstd field
video/s3fb.c
Used in 4bpp mode only, to control fb_setcolreg operation
video/vga16fb.c
When panning in non-8bpp, non-text mode, decrement xoffset
Do some other weird stuff when not 0
video/i810/i810_main.c
Select direct color mode when set to 1 (truecolor otherwise)
Fast forward a couple of years, hardware provides support for YUV frame
buffers. Several drivers had to provide YUV format selection to applications,
without any standard API to do so. All of them used the nonstd field for that
purpose:
media/video/ivtv/
Enable YUV mode when set to 1
video/pxafb.c
Encode pixel format in the nonstd field
video/sh_mobile_lcdfb.c
If bpp == 12 and nonstd != 0, enable NV12 mode
If bpp == 16 or bpp == 24, ?
video/omap/omapfb_main.c
Select direct color mode when set to 1 (depend on bpp otherwise)
Used as a pixel format identifier (YUV422, YUV420 or YUY422)
video/omap2/omapfb/omapfb-main.c
Select direct color mode when set to 1 (depend on bpp otherwise)
Used as a pixel format identifier (YUV422 or YUY422)
Those drivers use the nonstd field in different, incompatible ways.
Other related APIs
------------------
Beside the fbdev API, two other kernel/userspace APIs deal with video-related
modes and formats.
- Kernel Mode Setting (KMS)
The KMS API is similar in purpose to XRandR. Its main purpose is to provide a
kernel API to configure output video modes. As such, it doesn't care about
frame buffer formats, as they are irrelevant at the CRTC output.
In addition to handling video modes, the KMS API also provides support for
creating (and managing) frame buffer devices, as well as dumb scan-out
buffers. In-memory data format is relevant there, but KMS only handles width,
height, pitch, depth and bit-per-pixel information. The API doesn't care
whether the frame buffer or the dumb scan-out buffer contains RGB or YUV data.
An RFC[2] has recently been posted to the dri-devel mailing list to "add
overlays as first class KMS objects". The proposal includes explicit overlay
format support, and discussions have so far pushed towards reusing V4L format
codes for the KMS API.
- Video 4 Linux (V4L)
The V4L API version 2 (usually called V4L2) has since the beginning included
explicit support for data format, referred to as pixel formats.
Pixel formats are identified by a 32-bit number in the form of a four
characters code (4CC or FCC[3]). The list of FCCs defined by V4L2 is available
in [4].
A pixel format uniquely defines the layout of pixel data in memory, including
the format type (RGB, YUV, ...), number of bits per components, components
order and subsampling. It doesn't define the range of acceptable values for
pixel components (such as full-range YUV vs. BT.601[5]), which is carried
through a separate colorspace identifier[6].
YUV support in the fbdev API
----------------------------
Experience with the V4L2 API, both for desktop and embedded devices, and the
KMS API, suggests that recent hardware tend to standardize on a relatively
small number of pixel formats that don't require bitfield-level descriptions.
A pixel format definition based on identifiers should thus fullfill the
hardware needs for the foreseeable future.
Given the overlap between the KMS, V4L2 and fbdev APIs, the need to share data
and buffers between those subsystems, and the planned use of V4L2 FCCs in the
KMS overlay API, I believe using V4L2 FCCs to identify fbdev formats would be
a wise decision.
To select a frame buffer YUV format, the fb_var_screeninfo structure will need
to be extended with a format field. The fbdev API and ABI must not be broken,
which prevents us from changing the current structure layout and replacing the
existing format selection mechanism (through the red, green, blue and alpha
bitfields) completely.
Several solutions exist to introduce a format field in the fb_var_screeninfo
structure.
- Use the nonstd field as a format identifier. Existing drivers that use the
nonstd field for other purposes wouldn't be able to implement the new API
while keeping their existing API. This isn't a show stopper for drivers using
the FB_NONSTD_HAM and FB_NONSTD_REV_PIX_IN_B bits, as they don't need to
support any non-RGB format.
Existing drivers that support YUV formats through the nonstd field would have
to select between the current and the new API, without being able to implement
both.
- Use one of the reserved fields as a format identifier. Applications are
supposed to zero the fb_var_screeninfo structure before passing it to the
kernel, but experience showed that many applications forget to do so. Drivers
would then be unable to find out whether applications request a particular
format, or just forgot to initialize the field.
- Add a new FB_NONSTD_FORMAT bit to the nonstd field, and pass the format
through a separate field. If an application sets the FB_NONSTD_FORMAT bit in
the nonstd field, drivers will ignore the red, green, blue, transp and
grayscale fields, and use the format identifier to configure the frame buffer
format. The grayscale field would then be unneeded and could be reused as a
format identifier. Alternatively, one of the reserved fields could be used for
that purpose.
Existing drivers that support YUV formats through the nonstd field don't use
the field's most significant bits. They could implement both their current API
and the new API if the FB_NONSTD_FORMAT bit is stored in one of the nonstd
MSBs.
- Other solutions are possible, such as adding new ioctls. Those solutions are
more intrusive, and require larger changes to both userspace and kernelspace
code.
The third solution has my preference. Comments and feedback will be
appreciated. I will then work on a proof of concept and submit patches.
[1] http://en.wikipedia.org/wiki/Hold_And_Modify
[2] http://lwn.net/Articles/440192/
[3] http://www.fourcc.org/
[4] http://lxr.linux.no/linux+v2.6.38/include/linux/videodev2.h#L271
[5] http://en.wikipedia.org/wiki/Rec._601
[6] http://lxr.linux.no/linux+v2.6.38/include/linux/videodev2.h#L175
--
Regards,
Laurent Pinchart
More information about the dri-devel
mailing list