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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel