Author Topic: GNU/Linux fb and fbcon rotation  (Read 10915 times)

0 Members and 5 Guests are viewing this topic.

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #50 on: July 04, 2025, 09:03:45 am »
(While I was writing this, I was reminded of your screen blanking issues on the terminal console.  Do check man 4 console_codes and specifically printf '\033[9;Xm\033[14;Xm', especially with X set to zero.)

I will!

On the T23 I modified the Savage kernel driver, commented out all the blanking code and added a few lines to control the blanking hardware directly.

In short, the VGA chip has two AND circuits to enable/disable V-Sync and H-Sync. That's what the blanking does with the S3 chip.
Other chips (e.g. MGA) also allow you to disable the analogic part, so to blank { R, G, B }. You can fully disable the DAC.

It seems that the kernel driver can also handle console coherence and timer. Although it doesn't always seem to do what it promises.

But I don't care. Without the timer, the console never blanks.
And with my manual control, I can keep the VGA signal active or blanked.

Which is perfect for the VGA-grabber, used remotely; the goal was to reverse engineer the video grabber, and make it work well, making it usable rather than a stupid toy that takes some fixed predefined resolution, off-center pictures, ... the T23 laptop was just a "video source" and I couldn't bother with blanking that didn't work when I was connected remotely.

On the Japanese PDA, once again, the blanking causes problems. This time coherence problems, because when the screen blanks and I press a button to restart it, sometimes... it doesn't restart properly and the screen goes all-white.

kernel 2.6.24, kernel 5.4.229, same problem ... and it's very annoying.
I don't have time to investigate and I don't need to. So I think I'll hack the PXAfb the same way I hacked savagefb.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #51 on: July 09, 2025, 11:55:14 pm »
So, the fb library has been tested on different machines, and it's ok.
There is a problem with the PDA!

I don't know why, but the resolution is set to 320x240 instead of 640x480  :-//

How to change it without invoking external program like "fbset"?

Code: [Select]
boolean_t fb_mode_try_bpp
(
    p_fb_t p_fb,
    uint32_t bpp /* tested: { 32, 16, 8 } */
)
{
    my_id_t               fid[] = "fb_mode_try_bpp";
    boolean_t             ans;
    p_fb_var_screeninfo_t p_vinfo;
    uint32_t              fbfd;
    sint32_t              res;
    boolean_t             is_ok0;
    boolean_t             is_ok1;
    boolean_t             is_ok;

    p_vinfo = p_fb->p_vinfo;
    fbfd    = p_fb->fbfd;

    p_vinfo->bits_per_pixel = bpp; /* speculative */

    res    = (ioctl(fbfd, FBIOPUT_VSCREENINFO, p_vinfo));
    is_ok0 = (res isEqualTo 0);
    is_ok1 = (p_vinfo->bits_per_pixel isEqualTo bpp);
    is_ok  = (is_ok0 logicalAnd is_ok1);

    dbg_print_uint32(bpp, "Switching to ", " ... ");
    dbg_print_boolean_test(is_ok, "", "");
    dbg_print_nl();

    ans = is_ok;
    return ans;
}

This is how I probe the "bit per pixel". It worked on all the tested machines.
If I try to force resolution via p_vinfo->{x_res, y_res}, the framebuffer is not set correctly.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #52 on: July 10, 2025, 10:11:54 pm »
Tempted to replicate "fbset", embedding into my code.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #53 on: July 11, 2025, 02:12:22 pm »
How to change it without invoking external program like "fbset"?
You use FBIOPUT_VSCREENINFO with timing fields (.pixclock, .{left,right,upper,lower}_margin, .[hv]sync_len, .sync, .vmode) filled with coordinated video timings (with reduced blanking, if using LCD panels) matching .xres and .yres.
 
The following users thanked this post: DiTBho

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #54 on: July 11, 2025, 08:47:30 pm »
I have these values

Code: [Select]
mode "240x320"
    # D:  7.428  MHz
    # H:  22.787 kHz
    # V:  70.547  Hz
    geometry 240 320 240 320 16
    timings 134617 20 46 1 0 20 2
endmode

mode "480x640"
    # D:  51.999 MHz
    # H:  75.252 kHz
    # V: 116.851  Hz
    geometry 480 640 480 640 16
    timings 19231 46 125 1 0 40 3
endmode

LCD pannel, PXAfb driven
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #55 on: July 13, 2025, 03:44:29 pm »
Given fbset or /etc/fb.modes mode with
    geometry xres yres vxres vyres 16
    timings pixclock left right upper lower hslen vslen
the corresponding struct fb_var_screeninfo fields are
    .xres = xres,
    .yres = yres,
    .xres_virtual = vxres,
    .yres_virtual = vyres,
    .xoffset = 0,
    .yoffset = 0,
    .bits_per_pixel = 16,
    .grayscale = 0, // 0 for color mode; 1 for grayscale
    .pixclock = pixclock,
    .left_margin = left,
    .right_margin = right,
    .upper_margin = upper,
    .lower_margin = lower,
    .hsync_len = hslen,
    .vsync_len = vslen,
    .nonstd = 0,
    .width = 0,
    .height = 0,
    .activate = FB_ACTIVATE_NOW,
    .accel_flags = 0,
    .sync = 0,
    .vmode = 0,
    .rotate = 0,
    .colorspace = 0,
    .red = { .offset = 11, .length = 5, .msb_right = 0 },
    .green = { .offset = 5, .length = 6, .msb_right = 0 },   
    .blue = { .offset = 0, .length = 5, .msb_right = 0 },   
    .transp = { .offset = 0, .length = 0, .msb_right = 0 },

You can use .activate = FB_ACTIVATE_TEST first to only test if the values are acceptable, the driver rounding up any incompatible settings.
 
The following users thanked this post: DiTBho

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #56 on: July 13, 2025, 05:17:59 pm »
I'm seeing strange things.
bpp=32bit, RGB888 works perfectly on all my tested machines

On some laptops, if I force bpp=16 bits, with RGB565 I notice that white tends to be pink.
If I use 5 bit per channel, even for green, RGB555, then everything is fine

Code: [Select]
uint16_t rgb888_to_rgb565_get
(
    uint32_t rgb888
)
{
    uint16_t ans;
    uint16_t rgb565;
    uint8_t  r;
    uint8_t  g;
    uint8_t  b;

    r = ((rgb888 bitwiseAnd 0x00ff0000) shiftRight 16);
    g = ((rgb888 bitwiseAnd 0x0000ff00) shiftRight 8);
    b = ((rgb888 bitwiseAnd 0x000000ff) shiftRight 0);

    rgb565 = 0;
    rgb565 = rgb565 bitwiseOr((r shiftRight 3) shiftLeft 11);
    rgb565 = rgb565 bitwiseOr((g shiftRight 2) shiftLeft 5);
    rgb565 = rgb565 bitwiseOr((b shiftRight 3) shiftLeft 0);
(should be correct, but white is pink)

Code: [Select]
uint16_t rgb888_to_rgb565_get
(
    uint32_t rgb888
)
{
    uint16_t ans;
    uint16_t rgb565;
    uint8_t  r;
    uint8_t  g;
    uint8_t  b;

    r = ((rgb888 bitwiseAnd 0x00ff0000) shiftRight 16);
    g = ((rgb888 bitwiseAnd 0x0000ff00) shiftRight 8);
    b = ((rgb888 bitwiseAnd 0x000000ff) shiftRight 0);

    rgb565 = 0;
    rgb565 = rgb565 bitwiseOr((r shiftRight 3) shiftLeft 11);
//    rgb565 = rgb565 bitwiseOr((g shiftRight 2) shiftLeft 5);
    rgb565 = rgb565 bitwiseOr((g shiftRight 3) shiftLeft 5);
    rgb565 = rgb565 bitwiseOr((b shiftRight 3) shiftLeft 0);
white is white
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #57 on: July 13, 2025, 09:37:48 pm »
You do need to do a followup FBIOGET_VSCREENINFO to get the actual .red, .green, .blue, and .transp values.  The FBIOSET_VSCREENINFO with .activate = FB_ACTIVATE_NOW does not modify the values in the requested structure.

In particular, I suspect your 16-bit mode is actually ARGB1555, i.e.
    .red = { .offset = 10, .length = 5, .msb_right = 0 },
    .green = { .offset = 5, .length = 5, .msb_right = 0 },
    .blue = { .offset = 0, .length = 5, .msb_right = 0 },
    .transp = { .offset = 15, .length = 1, .msb_right = 0 },
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #58 on: July 14, 2025, 06:13:02 pm »
It seems it's RGB565, it works perfectly with savagefb, but something is wrong with the radeonfb

see ...

Code: [Select]
fb_init() on /dev/fb0
Switching to 16 ... success
fb_do_geometry0(): 1440 960 16
fb_angle_handler() angle=0
fb_angle_handler_000() bipp=16
sizeof(rgba[])={ 5 6 5 (0) }
offset(rgba[])={ 11 5 0 (0) }
...
(radeonfb)

Code: [Select]
...
    /*
     * read vinfo
     */
    io    = (ioctl(fbfd, FBIOGET_VSCREENINFO, p_vinfo));
    is_ok = (io isEqualTo 0);

...
    /*
     * how many bit?
     */
    rgb[0] = p_vinfo->red.length;
    rgb[1] = p_vinfo->green.length;
    rgb[2] = p_vinfo->blue.length;
    rgb[3] = p_vinfo->transp.length;
...

    /*
     * offset?
     */
    rgb[0] = p_vinfo->red.offset;
    rgb[1] = p_vinfo->green.offset;
    rgb[2] = p_vinfo->blue.offset;
    rgb[3] = p_vinfo->transp.offset;
...


(32bpp, rgb888, radeonfb)


(16bpp, rgb565, radeonfb)
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #59 on: July 14, 2025, 06:23:20 pm »
ATI Radeon 9700, 128 MByte Video ram

Code: [Select]
fb_init() on /dev/fb0
Switching to 16 ... success
fb_do_geometry0(): 1440 960 16
fb_angle_handler() angle=0
fb_angle_handler_000() bipp=16
sizeof(rgba[])={ 5 6 5 (0) }
offset(rgba[])={ 11 5 0 (0) }
(radeonfb, 16bpp)

Code: [Select]
fb_init() on /dev/fb0
Switching to 32 ... success
fb_do_geometry0(): 1440 960 32
fb_angle_handler() angle=0
fb_angle_handler_000() bipp=32
sizeof(rgba[])={ 8 8 8 (0) }
offset(rgba[])={ 16 8 0 (0) }
(radeonfb, 32bpp)
« Last Edit: July 14, 2025, 10:15:00 pm by DiTBho »
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #60 on: July 14, 2025, 10:27:16 pm »
One possible solution would be to use a variant of a /etc/fb.modes configuration file that names supported modes including RGB color components.
For example, you could use Debian fbset format, with
    rgb Rlen/Roff Glen/Goff Blen/Boff [ Tlen/Toff ]
to define the color component locations, ignoring the struct fb_var_screeninfo structure.

You can do a very lightweight parser by consuming input one token at a time.  For mode, endmode, geometry, timings, rgb, grayscale, and other keywords, you use one that gets the next ASCII alphabetic token (expected to be one of the aforementioned), skipping all leading whitespace and comments (comments to the end of line, with the following newline considered whitespace).  For the mode name, you need one that compares the (double-quoted) mode name to the desired mode name, only skipping leading whitespace.  For the nonnegative integer parameter values, you need to get the next value without crossing newline or comment lines, only skipping leading whitespace.  For rgb, you need to get the next length or length/offset pair (with offset defaulting to zero), only skipping leading whitespace.  For the rest, you need to get the next token expected to be true/yes/high/1 or false/no/low/0, only skipping leading whitespace.  You also need one that skips any parameters left on the line, including any comment, but leaves the input at/before the newline.
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #61 on: July 14, 2025, 10:43:52 pm »
More than anything, I don't understand why ati128fb and savagefb correctly represent RGB565 colors, while on radeonfb, white tends to be pink.
And have you seen the workaround for radeonfb: treat the green channel like the other two channels, so as if it were 5-bit rather than 6-bit.
Why does it work? Why do you need to do that?
Have you ever noticed that the returned var structure says the green channel uses 6 bits. This just doesn't make sense if then you have to thread the green channel like if it were 5-bits.

ati128fb, savagefb and radeonfb work perfectly with rgb888.

The pxa270fb only works with rgb565. I have to run more tests on it.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #62 on: July 14, 2025, 11:44:22 pm »
And have you seen the workaround for radeonfb: treat the green channel like the other two channels, so as if it were 5-bit rather than 6-bit.
No, but ever since KMS/DRI came along, the actual framebuffer drivers have very few users, and radeonfb in particular has changed a lot between 2.6.39.4 and 6.15.6.

I suspect the underlying issue is drivers/gpu/drm/drm_fourcc.c:drm_mode_legacy_fb_format(16, 15 or 16), since the issue is that struct fb_var_screeninfo gets .red,.green,.blue filled in per DRM_FORMAT_RGB565 but the actual mode uses DRM_FORMAT_XRGB1555.

Specifically, I think it is a bit-rot issue, or that particular card not correctly detected by the driver, with the "incorrect" fb_format value used in e.g. v5.4.229/drivers/gpu/drm/radeon/atombios_crtc.c:dce4_crtc_do_set_base() or v5.4.229/drivers/gpu/drm/radeon/atombios_crtc.c:avivo_crtc_do_set_base().  In both cases, the effective value is fb_format=0<<8 (XRGB1555), with the fb_var_screeninfo advertising values corresponding to fb_format=1<<8 (RGB565).  To me, this indicates that there is some issue in setting the correct fb_format value in one of the aforementioned functions, so that "effectively" fb_format==0 is used instead.  Or, it could be simply that these newer DRM-based "legacy FB compatibility" thingies expect a valid fourCC mode, because that's what all the users left do, and nobody has noticed this bug before.

One thing I would test first, is to set (struct fb_var_screeninfo).grayscale = V4L2_PIX_FMT_RGB565 (or one of the other values specified in <linux/videodev2.h>) when setting the mode.  Keep (struct fb_var_screeninfo).colorspace = 0 = V4L2_COLORSPACE_DEFAULT.  (Technically, the driver only respects that when (struct fb_fix_screeninfo).capabilities & FB_CAP_FOURCC is nonzero.)
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #63 on: July 15, 2025, 09:30:01 pm »
the actual framebuffer drivers have very few users, and radeonfb in particular has changed a lot between 2.6.39.4 and 6.15.6.
t] is nonzero.)

The "radeonfb" testing machine is an Apple PowerBook G4 @ 1.6Ghz, late 2005, running the kernel linux v2.6.26.
I have to update the kernel to something new.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #64 on: July 15, 2025, 09:42:03 pm »
Do you know any machine that supports RGB-1-555?

I'm actually a bit confused, especially given the different implementations I've seen: none of them clearly state this.
If you invoke 16bpp using the procedure I posted above, do you get RGB565 or, in some cases, RGB-1-555?
Both are 16bpp.

Are there graphics cards that support both, or is it mutually exclusive?

-

Anyway, I'm happy with RGB888; it works well and is very convenient.

I need to test it on an MGA1 (Matrox Millenium) and MGA2 (Matrox G450), because that's the graphics card I intend to install wherever possible:
- on the PowerMac G4
- on the HPPA C3750
- on my homemade x11 terminal

I bought several PCI cards

I have a savagefb on my T23 laptop, while I have an ATI128 on my PowerBook G3, and a PXA270fb on my Japanese PDA.

The PowerBook G4 isn't mine, so I don't know if my bootloader will ever run on that bloody radeonfb.

I mean, I don't know if it's worth investing more time on the radeon issue. The bootloader is pretty much complete for the Japanese PDA, but there are things that need to be rewritten and modified  :-//
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #65 on: July 15, 2025, 09:47:35 pm »
thingies expect a valid fourCC mode, because that's what all the users left do, and nobody has noticed this bug before.

From what I've seen, almost no one has ever used Radeon with 16 bpp; 24 bpp seems the most (and only) used mode, especially on Macs.

If so, it's a very old bug, dating back to the 2.6 kernel era.
Or maybe they fixed it at some point.

I'll have to ask the PowerBook G4 owner for permission to compile and install a recent kernel.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #66 on: July 17, 2025, 07:42:20 pm »
Is it DRM-based radeonfb, or the plain radeonfb framebuffer driver?  Check the kernel modules list (lsmod).

Here are the 16-bit RGB modes I know about (ignoring byte order differences between big-endian and little-endian):
$$\begin{array}{c|cccccccc:cccccccc|l}
\text{Bit}     & 15  & 14  & 13  & 12  & 11  & 10  &  9  &  8  &  7  &  6  &  5  &  4  &  3  &  2  &  1  &  0  & \text{FB use}     \\
\hline
\text{RGB565}  & r_4 & r_3 & r_2 & r_1 & r_0 & g_5 & g_4 & g_3 & g_2 & g_1 & g_0 & b_4 & b_3 & b_2 & b_1 & b_0 & \text{Common}     \\
\text{BGR565}  & b_4 & b_3 & b_2 & b_1 & b_0 & g_5 & g_4 & g_3 & g_2 & g_1 & g_0 & r_4 & r_3 & r_2 & r_1 & r_0 & \text{Historical} \\
\hline
\text{ARGB555} & \mathbf{a_0} & r_4 & r_3 & r_2 & r_1 & r_0 & g_4 & g_3 & g_2 & g_1 & g_0 & b_4 & b_3 & b_2 & b_1 & b_0 & \text{Overlays} \\
\text{ABGR555} & \mathbf{a_0} & b_4 & b_3 & b_2 & b_1 & b_0 & g_4 & g_3 & g_2 & g_1 & g_0 & r_4 & r_3 & r_2 & r_1 & r_0 & \text{Overlays} \\
\text{RGBA555} & r_4 & r_3 & r_2 & r_1 & r_0 & g_4 & g_3 & g_2 & g_1 & g_0 & b_4 & b_3 & b_2 & b_1 & b_0 & \mathbf{a_0} & \text{Overlays} \\
\text{BGRA555} & b_4 & b_3 & b_2 & b_1 & b_0 & g_4 & g_3 & g_2 & g_1 & g_0 & r_4 & r_3 & r_2 & r_1 & r_0 & \mathbf{a_0} & \text{Overlays}  \\
\hline
\text{RGB565/555} & r_4 & r_3 & r_2 & r_1 & r_0 & g_4 & g_3 & g_2 & g_1 & g_0 & \mathbf{g_4} & b_4 & b_3 & b_2 & b_1 & b_0 & \text{Std. green gamma} \\
\text{RGB565/555} & r_4 & r_3 & r_2 & r_1 & r_0 & \mathbf{?} & g_4 & g_3 & g_2 & g_1 & g_0 & b_4 & b_3 & b_2 & b_1 & b_0 & \text{Dbl. green gamma} \\
\text{BGR565/555} & b_4 & b_3 & b_2 & b_1 & b_0 & g_4 & g_3 & g_2 & g_1 & g_0 & \mathbf{g_4} & r_4 & r_3 & r_2 & r_1 & r_0 & \text{Std. green gamma} \\
\text{BGR565/555} & b_4 & b_3 & b_2 & b_1 & b_0 & \mathbf{?} & g_4 & g_3 & g_2 & g_1 & g_0 & r_4 & r_3 & r_2 & r_1 & r_0 & \text{Dbl. green gamma} \\
\hline
\text{(radeonfb)} & r_4 & r_3 & r_2 & r_1 & r_0 & \mathbf{?} & g_4 & g_3 & g_2 & g_1 & g_0 & b_4 & b_3 & b_2 & b_1 & b_0 & \text{?} \\
\hline
\text{ARGB444}    & a_3 & a_2 & a_1 & a_0 & r_3 &        r_2 & r_1 & r_0 & g_3 & g_2 & g_1 & g_0 & b_3 & b_2 & b_1 & b_0 & \text{Overlays} \\
\text{RGBA444}    & r_3 & r_2 & r_1 & r_0 & g_3 &        g_2 & g_1 & g_0 & b_3 & b_2 & b_1 & b_0 & a_3 & a_2 & a_1 & a_0 & \text{Overlays} \\
\text{ABGR444}    & a_3 & a_2 & a_1 & a_0 & b_3 &        b_2 & b_1 & b_0 & g_3 & g_2 & g_1 & g_0 & r_3 & r_2 & r_1 & r_0 & \text{Overlays} \\
\text{BGRA444}    & b_3 & b_2 & b_1 & b_0 & g_3 &        g_2 & g_1 & g_0 & r_3 & r_2 & r_1 & r_0 & a_3 & a_2 & a_1 & a_0 & \text{Overlays} \\
\end{array}$$
Whenever the GPU has a blitter (overlay engine, OpenGL or OpenGL ES support, or similar), it tends to support the 555-bit RGB modes.  If it has OpenGL or OpenGL support and an overlay engine with alpha blending, it tends to support the 4444-bit RGB modes also.

The 555-bit RGB modes that ignore the extra bit are either ARGB555/RGBA555/ABGR555/BGRA555, RGB565/555, or BGR565/555.

The RGB565/555 and BGR565/555 modes are available whenever the green component ramp (green gamma curve) is programmable.  The standard gamma curve one ignores the least significant bit, so that each even green component value and the following odd value will yield the same green component intensity.  The double gamma curve uses a 32-component gamma curve repeated twice, so that the green component intensity is the same for values g and g+32.

Component gamma curves are almost always programmable, but whether they are exposed via Linux framebuffer FBIOPUTCMAP ioctl does vary.  If supported, the parameter is a pointer to struct fb_cmapYou may need to use a separate call to set the 64 entries for green only (the three other pointers NULL), followed by a call to set initial 32 entries for all three color components (with transp NULL). For RGB565/555, you specify 64 entries, with .red and .blue having the actual ramp in indexes 0..31 and repeating it for 32..64 (but most drivers do not use the upper copy), and the .green depends on the approach you use as outlined in previous paragraph.  In all cases, 0x0000 corresponds to zero intensity, and 0xFFFF to maximum intensity of that color.  Always supply the three ramps in the same call; only .transp is optional.
« Last Edit: July 18, 2025, 01:23:34 am by Nominal Animal »
 
The following users thanked this post: DiTBho

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #67 on: July 17, 2025, 08:57:35 pm »
Is it DRM-based radeonfb, or the plain radeonfb framebuffer driver?  Check the kernel modules list (lsmod).

built-in kernel driver, radeonfb, it's not the DRM-based version.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #68 on: July 18, 2025, 01:18:12 am »
Okay, so the key kernel source file is v2.6.26.8/drivers/video/aty/radeonfb.h, v2.6.26.8/drivers/video/aty/atyfb_base.c, and v2.6.26.8/drivers/video/aty/radeon_base.c.

The comment in radeon_base.c:radeonfb_check_var() indicates the driver only supports 8-bit grayscale, ARGB555 (ignoring \$a_0\$), RGB565, and ARGB888 (ignoring \$a_0\$ through \$a_7\$).  Because these values are what you see in struct fb_var_screeninfo but do not correspond to the actual video mode the driver sets the GPU to, it is the mode-set code that is faulty.  Which is not that surprising, because DRM-based radeon support was mainlined by kernel 2.6.31, and most users and developers moving to that instead.

Again, note that the Linux kernel drivers do not expose all the actual hardware functionality, only what the developers have found necessary/viable/useful.

However, the v2.6.26 driver definitely supports both Standard and Doubled green gamma approaches for supporting 15-bit RGB via RGB565/555.  The FBIOPUTCMAP ioctl invokes v2.6.26/drivers/video/fbmem.c:fb_ioctl(), which ends up calling v2.6.26/drivers/video/fbcmap.c:fb_set_user_cmap(),  which ends up calling v2.6.26/drivers/video/fbcmap.c:fb_set_cmap().  This one uses the framebuffer-specific (struct fb_ops)->fb_setcmap() if it exists, and (struct fb_ops)->rb_setcolreg() for each entry otherwise.  On ATi Rage128, this is v2.6.26/drivers/video/aty/aty128fb.c:aty128fb_setcolreg(), on Radeons it is v2.6.26/drivers/video/aty/radeon_base.c:radeonfb_setcmap(), and on other ATi GPUs, it is v2.6.26/source/drivers/video/aty/atyfb_base.c:atyfb_setcolreg() (where the comment is incorrect: supplied red, green, and blue values are in 0..65535, not scaled to hardware at all).

In all cases (even for DRM emulated framebuffers), for the RGB565/555 and BGR565/555 modes, you use FBIOPUTCMAP with a struct fb_cmap that has .start = 0, .len = 64, .transp = NULL, the 32 initial entries in .red and .blue containing the gamma ramp from 0x0000 to 0xFFFF, inclusive, same repeated for the latter 32 entries, and all 64 entries in .green defining the green ramp, also mapped to 0x0000..0xFFFF.  For standard green gamma approach, the ramp value for each odd entry is the same as each preceding (even) entry, so that the least significant green bit is ignored, and this is the most widely compatible approach; for doubled green gamma approach, the ramp values for .green are the same they are for .red and .blue, so that the most significant green bit is ignored.

In practice, for your non-DRM radeonfb framebuffer, it could be possible that the gamma ramps are just incorrect, programmed to the doubled green gamma, and doing the FBIOPUTCMAP with proper gamma ramps fixes it –– whichever format (RGB565 or RGB565/555) you do want to use.

(In general, you want a gamma curve where the first nonzero empty differs from all-black, and halfway has the same perceptible brightness than a checkerboard pattern of full-intensity and black pixels.  Usually the ramp value at index \$0 \le i \lt N\$ is calculated using \$65535 \frac{e^{\gamma i/(N-1)}-1}{e^1 - 1} \approx 38139.84 \left(e^{\gamma i/(N-1)} - 1\right)\$, but due to peculiarities in human perception, the first few darkest values are often linear instead.  The difficulty in using such calibration images is that you have three adjustable values for red, three for green, and three for blue: first value sets the gamma (\$\gamma\$, default is 1.0), second the number of linear darkest entries, and the third the intensity of the second-darkest (darkest away from black) entry.  Most humans are not analytical enough to get "there" by themselves, adjusting these nine values, because there are often some tradeoffs, and the optimum set does depend on the ambient brightness and display brightness too.)

The same applies, if you only need 12 bit color, but have an use for the four extra bits per pixel, but do not want them to affect the visible color.  Then, you program RGB565 (all devices that I've seen supporting BGR565 have also supported RGB565), and set a 64-entry struct fb_cmap where each color ramp repeats four times.  Then, your 16-bit pixel colors are 0bWrrrrXYggggZbbbb in binary, where W, X, Y, and Z are the unused bits.  They are not contiguous and cannot be contiguous using standard Linux framebuffer userspace interface, unfortunately, unlike in ARGB444 or RGBA4444 modes.

(ARGB444 is particularly nice in that if you use \$a_0\$ through \$a_3\$ as a 4-bit depth/Z, you can do very fast Z-buffering by simply reading the old 16-bit pixel value, and writing the larger of old and new unsigned 16-bit pixel values, essentially *pixel=max(*pixel,value).)
 

Offline DiTBhoTopic starter

  • Super Contributor
  • ***
  • Posts: 5083
  • Country: gb
Re: GNU/Linux fb and fbcon rotation
« Reply #69 on: July 18, 2025, 09:56:23 pm »
Code: [Select]
# fb_bpp 16
Switching to 16 bpp ... success
trying rgb_8888 ... failure
trying rgb_0888 ... failure
trying rgb_0565 ... failure
trying rgb_1555 ... failure
trying rgb_0555 ... success
fb_angle_handler() angle=0
fb_angle_handler_000() bipp=16
setting intersposing handlers ... success

I implemented a new command to "probe" bpp/rgb-color.
It seems the aty128fb supports 16bpp rgb0555

Code: [Select]
# uname -r
2.6.26-wombat-apple-powerbook-G4-pismo

colors are perfect  :D :D :D
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 
The following users thanked this post: Nominal Animal

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: GNU/Linux fb and fbcon rotation
« Reply #70 on: July 19, 2025, 12:40:30 am »
FWIW, I've personally never found any visual benefit from the extra green bit; I do much prefer RGB555 myself (regardless of which position the unused bit is in).

By the way, does your 2.6.26 kernel export /sys/class/graphics/fb0/?  The contents may be interesting.

I still believe programming the color ramps explicitly to be useful.  For one, you can make it programmable (it's just 3×32 16-bit values), and then expect it to match sRGB, so no gamma adjustment is needed for typical images.  I'd recommend using just native byte order 98-word (196-byte) binary files, with the two first 16-bit unsigned integers containing a magic identifier (with all eight nibbles having different values) that detects both format and byte order.  Later on, you can write programs that read ICC color profiles and generate the corresponding color ramps you can use.

If you have framebuffers that do not behave exactly correctly, one possibility would be to create binary files with both requested and effective fb_var_screeninfo structures and the abovementioned color ramps, plus a small header that encodes the various sizes and endianness used.  If you stuff them under say /etc/fb.config.d/, the mode name is then the file name, and resource use (cpu time, I/O, and disk space used) is minimal (one 512-byte block will suffice for RGB555, 2048 bytes for RGB888), but flexibility and configurability will be maximal.  Wrap it all in a tiny library, perhaps exposing colorspace-converting rotating blitting operations, too.

If you want to do tear-free graphics, set up the virtual extents so that the height is at least three times the visible height, perhaps with a couple of pixels all around the visible area, but keeping both widths a multiple of 32 pixels, and the height of each virtual area a multiple of (struct fb_fix_screeninfo)->ypanstep (which will be zero if the hardware doesn't support it, but most do).  Then, you can do triple buffering using the FBIOPAN_DISPLAY ioctl.  (It takes a pointer to a struct fb_var_screeninfo, where xoffset and yoffset set the visible area within the virtual framebuffer; the v2.6.26/drivers/video/fbmem.c:fb_pan_display() handles the ioctl, and uses the per-framebuffer fb_pan_display() handler; v2.6.26/drivers/video/aty/aty128fb.c:aty128fb_pan_display() for aty128fb.
While some other framebuffer drivers support (struct fb_var_screeninfo)->activate=FB_ACTIVATE_VBL to auto-delay the operation until the next vertical blanking interval, I recommend using a FBIO_WAITFORVSYNC ioctl with the argument pointing to an int set to zero, followed by FBIOPAN_DISPLAY with updated xoffset/yoffset members and activate=FB_ACTIVATE_NOW.  You probably want to use a dedicated thread for this, with minimal stack, as the call blocks until a vertical refresh occurs (so will consume absolutely minimal CPU resources, and memory mostly by stack and thread info, around 16k typically).  Optimally, you'll have that thread do whatever compositing you need, too.
« Last Edit: July 19, 2025, 12:42:52 am by Nominal Animal »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf