GNU/Linux fb and fbcon rotation - Page 1
Forum section: electronics / general

author: DiTBho
author_rank: Super Contributor
timestamp: June 14, 2025, 07:18:22 pm
content: I know, from the documentation, that not all framebuffer drivers support rotation.Some might require custom patches or userland-support for rotation.Have you ever come across a GNU/Linux SBC that exposes the framebuffer on /dev/fb0, supports fbcon rotation but not /dev/fb0 rotation?Sysfs rotate attribute:/sys/class/graphics/fbcon/rotate <----- this attribute rotates the display of the text console/sys/class/graphics/fb0 <----- this attribute rotates the displaydesired rotation[0 degrees, 90 degrees, 180 degrees, 270 degrees]={ "0", "1", "2", "3" }e.g.to rotate the display 90 degrees clockwise using the sysfs attribute, you would execute:Code:echo "1" > /sys/class/graphics/fbcon/rotateThis perfectly works in my caseHowever ......if I try to display something graphical directly to /dev/fb0 (e.g. fbi, or dd if=image_rgb565.raw of=/dev/fb0), the result is rotated 90 degrees, and if I try to change the "rotate attribute" associated with fb0, nothing happensCode:# cat /sys/class/graphics/fb0/rotate0# echo "1" > /sys/class/graphics/fb0/rotate# cat /sys/class/graphics/fb0/rotate1("0" is the default value, associated with "0 degrees", but in my case the physical display is installed rotated 90°)What do you do in these cases? I wrote my userspace application to "rotate" the display in the software.Basically the idea is simple. I transform each (x,y) of source matrix into required (x,y) of final image.This "fixes" the problem, but ummm it looks dirty

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 15, 2025, 04:24:45 am
content: Quote from: DiTBho on June 14, 2025, 07:18:22 pmfbcon rotation is controlled byCONFIG_FRAMEBUFFER_CONSOLE_ROTATIONand only available when the framebuffer supports tile blitting,FBINFO_MISC_TILEBLITTING. It does not affect the framebuffer data orientation at all, only how text/glyphs are blitted to it.Frame buffer rotation depends on whether the underlying hardware supports it. MostDRMdrivers support frame buffer rotation, but not all of them either. I'm pretty sure AMD, ARM HDLCD, ARM Mali, ARM Komeda, Atmel HLCDC, Intel i915, NXP i.MX8MQ, Mediatek DRM, MSM DRM, OMAP 2/3/4 DRM, Rockchip DRM, Unisoc DRM, ST MIPI or LVDS, NVidia Tegra, and Broadcom VC4 do.I do not believe any of the legacy framebuffer devices like vesafb, Intel i810, imxfb support framebuffer rotation, but I haven't checked.You can find the list of DRM drivers indrivers/gpu/drm/in the kernel sources, and legacy framebuffer drivers indrivers/video/fbdev/.Quote from: DiTBho on June 14, 2025, 07:18:22 pmYes, this is what we do.Note that when using small display modules with internal controllers like ILI9341, ILI9488, ST7789 etc., we have a related problem. While the display controller can "rotate" the display – the framebuffer orientation –, the display scanning/refresh is always done in the one fixed orientation. Thus, using the controller rotation property, easily leads totear effect, where the display refresh catches up with the data update, showing partially old and new data. The only way to avoid this is to use the native display orientation in the controller, and "rotate" the graphics in software.Quote from: DiTBho on June 14, 2025, 07:18:22 pmWhat I like to do, is to use my own renderers/blitters that can rotate and mirror the data being copied.At the core is the fact that if you have 0≤x<W and 0≤y<H, pixel (x,y) is atorigin+X×x+Y×y, where X and Y are the logical horizontal and verticalstrides, and may be positive or negative. When blitting, if you know your blitting region is within the display boundaries, and current pixel is ataddr, you know that the pixel to logically right is ataddr+X and the pixel to logically down is ataddr+Y.originitself can point at any of the four corner pixel addresses in the display. As long as the framebuffer pixel size is 1, 2, or 4 bytes, you can use corresponding unsigned 8-bit, 16-bit, or 32-bit accesses to update each pixel. 24-bit (3 bytes per pixel) suffers from every second pixel having an odd address, and can thus incur unaligned access penalties, so I recommend against it.Note that this is also well suited for run-length encoding BW images. I also like to use 4-bit alpha storage for antialiased fonts and glyphs, with each byte specifying the opacity of a pair of logically horizontal pixels, with width always even. A look-up table with 16 entries will contain the values used for 0 (background) .. 15 (foreground), allowing any foreground + background pair be used with extremely fast glyph rendering (especially if your data cache is large enough you can cache full bytes, 256 entries with two color specs each; 1024 bytes for 16-bit color). An antialiased glyph set withNglyphs, eachw×hpixels, takesN×w×h/2 bytes (which turns out to not be that much – 5376 bytes for ASCII 8×14, 18432 for ASCII 16×24). You can similarly support 1 and 2 bits per pixel. 3 bits per pixel is visually almost identical to 4 bits per pixel on RGB555 and RGB565, but you'll want to work in units of 5 or 10 pixels (16 or 32 bits). And always pre-lookup the opacity-to-framebuffer data, not compute it on a per-pixel basis.Use an optimized routine whenever the entire glyph is visible, and a slow one covering the entire glyph when only partially visible, omitting only (the lookup and) the write when outside the visible region. The partial ones are rare, so the extra cost of tracking and testingxandy(instead of just the pixel address) is okay.In my opinion, this is not "dirty" at all. Kinda pretty in its simplicity, actually.

author: DiTBho
author_rank: Super Contributor
timestamp: June 15, 2025, 08:02:39 am
content: Quote from: Nominal Animal on June 15, 2025, 04:24:45 amAt the moment I am working with Xscale PXA270.It seems the SoC only offers a simple framebuffer.

author: DiTBho
author_rank: Super Contributor
timestamp: June 16, 2025, 12:08:30 pm
content: Ummm, yesterday night I moved src to my mac-mini/intel-2009.It is used remotely, via ssh console, however, despite offering text console via fbcon using "nouveau" driver, it does not expose the framebuffer devname.There is no /dev/fb0!The "testing machine" was an IBM ThinkPad T23, which comes with "S3 SuperSavage" frame buffer device.The "savagefb" correctly exports the framebuffer devname, /dev/fb0WTF on the macmini/intel ?!?

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 16, 2025, 02:11:48 pm
content: Quote from: DiTBho on June 16, 2025, 12:08:30 pmCheck your kernel config, and make sureCONFIG_DRM_FBDEV_EMULATIONis enabled.If it is not enabled, DRM drivers will not provide/dev/fb0even if they do support fbcon; this is because they use the GPU-specific (and accelerated) blit operations via the DRM layer directly.

author: DiTBho
author_rank: Super Contributor
timestamp: June 16, 2025, 10:09:21 pm
content: Quote from: Nominal Animal on June 16, 2025, 02:11:48 pmIt was already setCode:# nano .config..CONFIG_DRM=y# CONFIG_DRM_DEBUG_MM is not setCONFIG_DRM_KMS_HELPER=yCONFIG_DRM_FBDEV_EMULATION=yCONFIG_DRM_FBDEV_OVERALLOC=100...(kernel-6.1.7-x86_64-macmini-2009)

author: DiTBho
author_rank: Super Contributor
timestamp: June 16, 2025, 10:47:18 pm
content: Quote from: Nominal Animal on June 15, 2025, 04:24:45 am"fbi" is a bit silly: refuses to rotate anything but only jpeg.I have two options here1) try to add software rotation in kernel space to make "fbi" happy2) improve my program to replace "fbi", just ... at the moment, I am supporting only "ppm-p6/rgb565"I have already written a tool that "converts" "png" to "ppm-p6/rgb565", but umm.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 17, 2025, 05:37:24 am
content: Quote from: DiTBho on June 16, 2025, 10:09:21 pmHow annoying.For what it is worth, I don't think/dev/fb0rotation support is very common; I definitely would not want to rely on it.To repeat, what I use for RGB555/RGB565 is something likestatic volatile uint16_t *pixel;static int_fast16_t xsize;static int_fast16_t ysize;static int_fast16_t xstride;static int_fast16_t ystride;so that when(x >= 0 && y >= 0 && x < xsize && y < ysize), pixel (x,y) is atpixel[x*xstride+y*ystride]. (Note that herexstrideandystrideare in units ofsizeof *pixel, i.e. in 16-bit words.)When blitting a rectangular region that is within the viewport, the logical top left corner is atvolatile uint16_t *curr = pixel +left*xstride +top*ystride. I typically just advance bycurr += xstridein the inner loop, and byystride-width*xstridein the outer loop.When copying non-overlapping regions on screen, or from pre-rotated offscreen pixmaps, it is trivial to obtain the true minimum address. Ifxstrideis negative, substract its magnitude fromcurr. Ifystrideis negative, subtract the magnitude ofxstride*ystridefromcurr. The inner loop increment is the smaller of the magnitudes ofxstrideandystride, and the outer axis stride is the larger of their magnitudes (making the outer loop incrementlarger-width*smaller).When copying overlapping regions on screen, you do need to adjust the scanning direction anyway, to read the overlapping region before overwriting it.If you support blitting to screen with 90-degree rotation and mirroring support, you do need to adjust the scanning direction, but because the framebuffer tends to be large (wide) and pixmaps small, it is usually beneficial to do the scanning in the native order for the framebuffer, and in weird order in the pixmap. The same stride logic as above will work very well for any byte-aligned pixmap data.For packed pixmaps, for example 4-bit ones, where you expand the input using a small look-up table of colors, use 8/16/32-bit storage "words", with each pixmap specifying the number of bits (and therefore the look-up table size) and the right-shift within each storage word. That allows some very interesting options, like ten 3-bit pixmaps and one 2-bit one, or any other combination, in the same storage area –– with a very simple blitting function with very optimized innermost loop. The added cost is only one bit shift per output pixel! (I've looked at using 4-bit pairs in a byte, and the code complexity is just ridiculous compared to storing two different 4-bit pixmaps in the same bytes.) For packing, just consider the storage area as a 2D bit array (pixel × depth), where each pixmap is a contiguous rectangle of bits. There is no reason for pixmaps occupying different bits in the same bytes to be the same size, it's all only a matter of packing their storage efficiently. Fast "binning" rectangular packing algorithms tend to be pretty fast but good at packing e.g. fonts/glyphs at runtime, for example.(If it is not clear, I am referring to things like using antialiased fonts with very little additional computational work or memory use. I like my AA glyphs!)All of the above applies to 8-bit (RGB332, ARGB2222) and 32-bit pixels. 24-bit pixels are annoying to deal with, as most instruction sets do not have 24-bit loads and stores, so I do it as three byte reads/writes, withvolatile unsigned char *curr, and strides in bytes (i.e., both strides are divisible by three). Annoying, but works.fbida(github– yes, the utility is still namedfbi) is weird in that instead of changing how it renders the images to the framebuffer,it actually transposes the JPEG data. Because JPEG uses IDCT on fixed-size square blocks of pixels, the modification is lossless.

author: DiTBho
author_rank: Super Contributor
timestamp: June 17, 2025, 07:59:47 am
content: Quote from: Nominal Animal on June 17, 2025, 05:37:24 amIf you have several applications that access the framebuffer directly, you have to write a library that handles the rotate, and link that library to all the applications.If instead it is implemented in kernel space, you can avoid having to link it and fbi also works without having to hack it.pros and cons

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 17, 2025, 10:52:46 am
content: The main drawback for the kernel option is the overhead: having a second framebuffer always resident in memory, and having to periodically copy between the two (in a way that may not be easily DMA'ble, although some SoCs do have a "2D DMA" or pixel engine that can offload this, as can most DRM drivers). 320×240×16bit is just 153,600 bytes, but 1024×600×16bit it is 1,228,800 bytes, and 1920×1080×32bit it is 8,294,400 bytes. It quickly adds up when you're limited to just a few (tens of) megabytes of RAM.Thus, I do lean towards the library option myself. If you implement separate blitting functions for 8bpp, 16bpp, 24bpp, and 32bpp, and use pre-rendered fonts, the library option is actually pretty straightforward, even if you use anti-aliased/hinted fonts. 255 glyphs at 12×21 fixed size only needs about 25k of storage if you use 3 bits per pixel opacity. Kerning and spacing and variable size adds a few bytes per glyph. Rendering to 8/16/32bpp is fast, and you can do any combination of 90 degree rotations and mirroring without extra cost.Conversion of image libraries has a related memory use issue. On one hand, they can be modified to access the image storage using the method I showed above. Unfortunately, this goes deep into the guts of said libraries, and can be a lot of work and tears to get working right. On the other hand, using a temporary buffer to hold the image "wastes" memory, but is easy to do; one just blits the image buffer to the framebuffer instead of letting the library render it directly to the framebuffer.

author: DiTBho
author_rank: Super Contributor
timestamp: June 17, 2025, 08:37:23 pm
content: Google suggestsuvesafb+ v86d, which means "x86 emulating x86".No way, I am not willing to do that crazy stuff to have /dev/fb0

author: DiTBho
author_rank: Super Contributor
timestamp: June 17, 2025, 08:54:33 pm
content: Quote from: Nominal Animal on June 17, 2025, 10:52:46 amUmm, I was thinking about applying an "index mapper" to the dev-name write-and-read kernel moduel primitives. So "rotation" is only executed when something tries to write or read /dev/fb0.Code:source|aA1 aA2 aA3 aA4 ||bBq bBw bBe bB* |90 counterclockwise|aA4 bB* ||aA3 bBe ||aA2 bBw ||aA1 bBq |270 counterclockwise|bBq aA1 ||bBw aA2 ||bBe aA3 ||bB* aA4 |Code:char_t source[] ={'a','A','1', 'a','A','2', 'a','A','3', 'a','A','4','b','B','q', 'b','B','w', 'b','B','e', 'b','B','*',};p_cell0->data.cell_size = 3;p_cell0->data.row_n = 2;p_cell0->data.col_n = 4;p_cell0->data.p = source;matrix_show2(p_cell0, icell_get, "source");matrix_show2(p_cell0, icell_90_get, "90 counterclockwise");matrix_show2(p_cell0, icell_270_get, "270 counterclockwise");}{ icell_get(), icell_90_get(), icell_270_get() } are callbacks.They don't "copy" anything, they just return an index.They work as "index mapper"Code:void matrix_show2(p_cell_t p_cell,icell_get_t iget, /* callback */p_char_t p_msg){p_char_t p_data; /* ASCII/8bit */uint32_t row_n;uint32_t col_n;uint32_t cell_size;uint32_t i0;uint32_t irow;uint32_t icol;uint32_t isel;char_t value;p_data = p_cell->data.p;row_n = p_cell->work.row_n;col_n = p_cell->work.col_n;cell_size = p_cell->data.cell_size;print_string(p_msg, "[", "]\n");for (irow = 0; irow < row_n; irow++){print_string("|", "", "");for (icol = 0; icol < col_n; icol++){for (isel = 0; isel < cell_size; isel++){i0 = iget(p_cell, False, irow, icol, isel);value = p_data;print_char(value, "", "");}print_string(" ", "", "");}print_string("|", "", "\n");}print_nl();}

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 18, 2025, 05:45:57 am
content: Quote from: DiTBho on June 17, 2025, 08:54:33 pmDo any/all of your userspace applications use the read()/write() interface? If they do, then that sure should work fine.Everything I've ever written to work on top of a plain framebuffer usesaddr= mmap(NULL,size-in-bytes, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE,fd-to-dev-fb0, 0). Interposing accesses to mapped memory is horribly slow and yukky, involving page fault handlers and such.

author: DiTBho
author_rank: Super Contributor
timestamp: June 18, 2025, 07:59:26 am
content: Quote from: Nominal Animal on June 18, 2025, 05:45:57 amYes, mine are all written that way. However... there is no guarantee that other programs are written the same way, and boy, that's a problemQuote from: Nominal Animal on June 18, 2025, 05:45:57 amd'oh

author: DiTBho
author_rank: Super Contributor
timestamp: June 18, 2025, 09:56:07 pm
content: What about interposing from the userspace an application that mmaps /dev/fb0 to a buffer, and on this buffer you "soft-rotate" by interposing?good/bad ?

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 19, 2025, 10:50:44 am
content: It can be done in an userspace interposer (preload library), using a worker thread and a SIGSEGV signal handler, on a per-page basis. Using RGB565 and 4k pages, each page contains 2048 pixels, or two rows at 1024×hhhresolution. The downside is the coarseness of a page. At any standard resolutions, an application drawing a vertical line across the entire framebuffer it sees will damage all pages in the framebuffer.The idea is that normally, the shadow framebuffer pages are mapped read-only. Whenever a write access occurs, the SIGSEGV is caught, the page marked as damaged, and remapped read-write. (This means the SIGSEGV handler does not need to do any instruction parsing.) Further modifications to the same page do not raise the signal.Periodically – at most, once per vertical retrace, or by timer, say every 20ms ––, the worker thread checks all damaged pages, marking each clean, remapping read-only, and blitting rotated to the actual framebuffer.As is usual with SIGSEGV handlers, it is this handler that is the main headache. Specifically, handling the race condition when one of the threads writes to the framebuffer during damaged page writeout – fortunately we do not need to interpret any machine instructions or determine the actual access here, because the kernel-raised signal contains all information we need, and the thread will simply afterwards re-run the instruction. The simple option is to pause such threads, using a lockless data structure to track the TIDs of such paused threads, and wake them up when the damage worker thread has checked all pages in the buffer. Because of pthreads overhead and POSIX-Linux differences, you'd want to use raw syscalls for this. Doable, but not simple.In the kernel, in a "rotated framebuffer" driver –– see various virtual framebuffer drivers for examples ––, the same can be achieved by using a RAM shadow copy of the framebuffer, and tracking the page dirty bit. This is much cleaner and somewhat more efficient as well. Effectively, this is just a special case of swapping memory, and those code paths are well used and optimized in Linux.The difference to using a simple periodic copy-blitting the entire framebuffer is, of course, that when the contents of the framebuffer do not change, there is no overhead either. Reads from the framebuffer are always fast (no signal raised), and of page-local writes, only the first one incurs the overhead (of the signal, and the eventual cleanup blitting by the worker).

author: DiTBho
author_rank: Super Contributor
timestamp: June 25, 2025, 07:27:31 pm
content: Code:p_fb_fix_screeninfo_t p_finfo;uint32_t line_length;line_length = p_finfo->line_length;Code:# hinvfb: 480x640,16bitwhy does the struct "fb_fix_screeninfo" need line_lenght?Code:line_length=960

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 25, 2025, 07:48:12 pm
content: Quote from: DiTBho on June 25, 2025, 07:27:31 pmIt is used in the case where the width in pixels times the bits per pixels is not sufficiently aligned for the hardware, and there is a partial pixel at the end; in that case,line_length*8 >bits_per_pixel*xres_virtual. See thekernel FB APIfor further details.I don't recall ever seeing such in practice, asxres_virtualtends to be a multiple of big enough power of two so that even with 24-bit pixels the line length in bytes is sufficiently aligned (a multiple of a high enough power of two). For example, 480*3 = 1440 = 45*32, 640*3 = 1920 = 30*64, 1440*3 = 4320 = 135*32, and so on.

author: DiTBho
author_rank: Super Contributor
timestamp: June 27, 2025, 12:10:35 pm
content: Something weird is happening with the framebuffer.If I run mmap /dev/fb0, and fill the graphics area with an image, but the screen is in blank mode, when I press a key to resume from blanking, the framebuffer is not updated with the graphics image./sbin/agetty is not running, so the screen is not associated with any tty console.Once the screen resumes from blanking, my code does the work and I see the image displayed on the screen

author: DiTBho
author_rank: Super Contributor
timestamp: June 27, 2025, 12:16:21 pm
content: For some weird reasons I cannot switch to 24-32bit color mode.The only working mode seems 16bit, which means rgb565.My image is rgb888Code:from rgb888 to rgb565rgb565 = ((r>>3) << 11) | ((g>>2) << 5) | b >> 3------- 5-bits----------------- 6-bits------------- 5-bits------------------------------------- 16-bitsHowever, converting RGB888 to RGB565 results in a "yellowish tint", probably due to the different bit allocations for the green channel in each format.RGB888 uses 8 bits for each color (R, G, B)RGB565 uses 5 bits for red, 6 bits for green, 5 bits for blueThe original green component in my RGB888 image is at the highest/lowest value, because the image is black/white.How to compensate?

author: DiTBho
author_rank: Super Contributor
timestamp: June 27, 2025, 12:18:33 pm
content: ideally I would be tempted to hack the framebuffer kernel moduleand remove the blanking like I didhere, because there is no userspace way to control it ...... or rather... it doesn't work as it should.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 27, 2025, 01:07:48 pm
content: Quote from: DiTBho on June 27, 2025, 12:16:21 pmThis works but may be sensitive to the types (signedness) ofr,g, andb. Yellow tint is likely an effect of LSBs of red flowing into MSBs of green, or values of blue with MSB set being sign-extended tointdue to integer promotion.If you have RGB888 inuint32_t c, thenuint_fast16_t rgb565 = ((c >> 8) & 0xF800) | ((c >> 5) & 0x7E0) | ((c >> 3) & 0x1F);converts it to RGB565. Make sure you do your masking and shifts in correct order if you combine them, so that red does not affect green, nor green blue.If you have the three components inr,g,b, I'd useuint_fast16_t rgb565 = (((uint_fast16_t)(((uint8_t)r) >> 3)) << 11)| (((uint_fast16_t)(((uint8_t)g) >> 2)) << 5)| ((uint_fast16_t)(((uint8_t)b) >> 3));which I agree is annoying to read, unless your editor colors nested parentheses, but the explicit casts ensure it is done correctly.

author: DiTBho
author_rank: Super Contributor
timestamp: June 27, 2025, 02:03:51 pm
content: { r,g,b } are already uint8_tbut, even with your solution, it's still "yellowish tint"

author: gf
author_rank: Super Contributor
timestamp: June 27, 2025, 03:12:05 pm
content: Quote from: DiTBho on June 27, 2025, 12:16:21 pmHow do you know what RGB888 would look like if you can't enable 24-bit mode?Are you sure it wouldn't look yellowish, too? Can you rule out that it's from the display?And of course, the conversion to RGB565 introduces truncation or rounding errors.Rounding to the nearest integer instead of truncating the fractional part would result in a lower mean squared error over all 16,777,216 RGB888 colors. Vector quantization could reduce the MSE even further, but I think it would become overly complicated.Another question is: What are the right scaling factors? 32:256 (64:256 for G), or 31:255 (63:255 for G)? Assuming that white is represented by either RGB888=255,255,255 or by RGB565=31,63,31, then rather the odd factors would be the right ones, in order that white888maps exactly to white565. The odd ones are, however, inconvenient for a fast calculation (but one could use a pre-calculated LUT to map the 8-bit values to corresponding 5- or 6-bit values).

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 27, 2025, 05:49:25 pm
content: Quote from: DiTBho on June 27, 2025, 02:03:51 pmThen it isn't the conversion to RGB565 that causes the tint, but something else.Have you drawn an RGB565 test image or color bar image yet, to check if the display is OK?

author: DiTBho
author_rank: Super Contributor
timestamp: June 27, 2025, 06:38:28 pm
content: Quote from: Nominal Animal on June 27, 2025, 05:49:25 pmWith fbi, yes.I converted my png image into pnm/P6 (P6 means "rgb888, binary"), and I am using this file.Code:2025-06-13--23-33-21---2025-06-13--23-36-49 - [ media-libs/netpbm ] - success - DiTBho@dev2.38/13(pngtopnm image.png image.pnm)The original image is black/white, there are no other colors.I think I will use a full scale color image.But there is an other problem now.I moved the code to an IBM ThinkPad T23, running GNU/linux on a Savage S3 video card.And ....Code:# hinv...fb0: 800x600,8...8bit color mode only, wtf!?!PlusCode:xres = p_vinfo->xres; /* virtual */yres = p_vinfo->yres; /* virtual */yres_virtual is 600, but xres_virtual is 4096, wtf!?!?Code:# fbsetmode "800x600-60"# D: 40.000 MHz, H: 37.879 kHz, V: 60.317 Hzgeometry 800 600 800 4096 8timings 25000 88 40 23 1 128 4hsync highvsync highaccel truergba 8/0,8/0,8/0,0/0endmodeso i have to add some more code to handle this color mode too8bit16bit18bit <---- found used in a PDA24bit32bit ?!?I don't want to use SDL or other stuff, so writing a "bare metal" frambuffer library with primitives { pixel, line, rect } that is universally usable on all GNU/linux SBCs seems to be much more complicated than expected.

author: DiTBho
author_rank: Super Contributor
timestamp: June 27, 2025, 08:53:11 pm
content: Quote from: DiTBho on June 27, 2025, 06:38:28 pmlooking at the kernel source, it seems - by default - the framebuffer driver may have set an oversized yres_virtual to "support VT scrolling" via the "panning" interface.makes sense, but umm

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 27, 2025, 09:14:23 pm
content: Quote from: DiTBho on June 27, 2025, 06:38:28 pmThe 800x600,8 mode is what thesavagefb driver reports for LCD panelswhen probing (i.e. "by default"). You can use VESA CVT reduced timings to set different video modes, and thesavagefb.mode_optionkernel command line parameter to set the video mode using kernelmodedbsyntax.AFAIK, T23 has a LCD panel with native resolution of either 1024×768 or 1400×1050. The corresponding LCD panel (CVT reduced) modelines are1024x768MR-BPP@60and1400x1050MR-BPP@60, whereBPPis bits per pixel, i.e. 16, 24, or 32.Therefore, I'd reboot the machine with Linux boot command linesavagefb.mode_option=1024x768MR-16@60orsavagefb.mode_option=1400x1050MR-16@60before anything else.Quote from: DiTBho on June 27, 2025, 06:38:28 pmAFAIK, T23 has an S3 SuperSavage IX/C graphics "card" with 16 MB of dedicated frame buffer memory.xres_virtualjust means that in this particular mode (800x600-8) each scanline is 4096 bytes long.Usually it is theyres_virtualthat is extended to fill the entire framebuffer, though.The 2D accelerator in Savage is such that xres_virtual and yres_virtual must not exceed 4096 (0x1000).You can see the details in thedrivers/video/fbdev/savage/savagefb_driver.c:savagefb_probe()function.Put simply, to boot Linux using optimal LCD framebuffer mode, you do need to use thesavagefb.mode_option=kernel commandline option.Quote from: DiTBho on June 27, 2025, 06:38:28 pmI only supportfb_fix_screeninfo.type == FB_TYPE_PACKED_PIXELS &&(fb_fix_screeninfo.visual == FB_VISUAL_TRUECOLOR ||fb_fix_screeninfo.visual == FB_VISUAL_DIRECTCOLOR) &&(fb_var_screeninfo.bits_per_pixel == 8 ||fb_var_screeninfo.bits_per_pixel == 16 ||fb_var_screeninfo.bits_per_pixel == 32)and if I ever encounter one,fb_fix_screeninfo.type == FB_TYPE_FOURCC && fb_fix_screeninfo.visual == FB_VISUAL_FOURCCwithfb_var_screeninfo.grayscalehaving one of the 8-bit, 16-bit, or 32-bitV4L2_PIX_FMT_*[0-9]*X?values defined in<linux/videodev2.h>, since they map to compatible modes with component positions and sizes depending on the fourcc code.That means I only need three variants:Code:// unsigned char *fb_origin;// int32_t fb_xstride, fb_ystride, fb_xsize, fb_ysize;// The following functions assume (x >= 0 && y >= 0 && x < fb_xsize && y < fb_ysize)static void set_pixel_none(const int32_t x, const int32_t y, const uint32_t c) {// Nothing}static void set_pixel_8bpp(const int32_t x, const int32_t y, const uint32_t c) {*(fb_origin + x*fb_xstride + y*fb_ystride) = c;}static void set_pixel_16bpp(const int32_t x, const int32_t y, const uint32_t c) {*(uint16_t *)(fb_origin + x*fb_xstride + y*fb_ystride) = c;}static void set_pixel_32bpp(const int32_t x, const int32_t y, const uint32_t c) {*(uint32_t *)(fb_origin + x*fb_xstride + y*fb_ystride) = c;}// Use the function pointer to avoid switch statement.static void (*set_pixel)(int32_t, int32_t, uint32_t) = set_pixel_none;For filled rectangles and blitting, I do implement three different variants, depending on the target bits per pixel.For lines, curves, arcs I use theset_pixelfunction pointer.In 2D, there are 8 possible axis-aligned orientations including mirroring through either or both axes, and they can be reached if you use one bit for X-Y transpose, one bit for mirroring in X, and one bit for mirroring in Y, applied in that order (for example). You only need 8×3 = 24 bit lookup table to find which is which rotated by 90 degrees clockwise, and another for counterclockwise, and another for the inverse rotation. This means that a blitting function that supports blitting some source pixmap to the framebuffer in any orientation, can optimize the draw order to be consecutive in framebuffer, but "random" order in pixmap. If the framebuffer is larger than the pixmap, this yields better cache locality, and can speed up blits a bit.For me, the most important blitting routine is one that expandsN-bit data to full color on framebuffer. The blitting routine gets the reference corner coordinates on framebuffer, the drawing orientation (0..7), the origin of the pixmap, the stride and size of the pixmap, the data shift andN, and the (1<<N)-entry color table (inuint32_tformat).The drawing orientation is applied to the pixmap origin and strides. Then, the framebuffer strides are compared to the pixmap strides, and the framebuffer strides and reference corner adjusted so that blitting is consecutive in framebuffer access. Finally, the blitted rectangle is compared to valid coordinates, and only the visible portion is blitted. For each pixmap byte (or uint32_t), it is first shifted right by the data shift amount, then ANDed with(1<<N)-1.While that means that bits 0..3 of the pixmap bytes hold one pixmap, and the higher bits some other pixmap or pixmaps, this minimizes the per-pixel work and allows very fast blitting. For anti-aliased fonts, the first color table entry is the background, the last is the foreground, and the rest of the entries blend between the two.Interpolating the middle colors in L*a*b or HSL color space often yields visually better results than interpolating RGB values, unless one of the end colors is black or white.

author: DiTBho
author_rank: Super Contributor
timestamp: June 28, 2025, 09:46:54 am
content: can't you change the bpp mode at runtime?I tried this methodCode:...is_ok = False;if (is_ok isEqualTo False){is_ok = fb_mode_try_32bit(p_myscreen);}if (is_ok isEqualTo False){is_ok = fb_mode_try_16bit(p_myscreen);}Code:private boolean_t fb_mode_try_32bit(p_myscreen_t p_myscreen){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_myscreen->p_vinfo;fbfd = p_myscreen->fbfd;/** try setting an { 0,8,8,8 } pixel format*/p_vinfo->bits_per_pixel = 32;p_vinfo->red.offset = 0;p_vinfo->red.length = 8;p_vinfo->green.offset = 8;p_vinfo->green.length = 8;p_vinfo->blue.offset = 16;p_vinfo->blue.length = 8;p_vinfo->transp.offset = 0;p_vinfo->transp.length = 0;res = (ioctl(fbfd, FBIOPUT_VSCREENINFO, p_vinfo));is_ok0 = (res isEqualTo 0);is_ok1 = (p_vinfo->bits_per_pixel isEqualTo 32);is_ok = (is_ok0 logicalAnd is_ok1);if (is_ok isEqualTo True){p_myscreen->width = p_vinfo->xres;p_myscreen->height = p_vinfo->yres;p_myscreen->depth = p_vinfo->bits_per_pixel;}dbg_print_boolean_test(is_dbg, is_ok, "Switching to 32bpp mode ...", "\n");ans = is_ok;return ans;}It seems working

author: DiTBho
author_rank: Super Contributor
timestamp: June 28, 2025, 09:52:18 am
content: if it's correct, the problem is: how to "probe" all the supported (by kernel and hw) bpp-modes?guinea pigs (humor for "testhing machines"):- mac-mini/ppc-g4, radeonfb- Thinkpad-T23, savagefb- PDA, PXA270-fb...- others?

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 28, 2025, 12:37:06 pm
content: Quote from: DiTBho on June 28, 2025, 09:46:54 amOf course you can. All devices I have that support VGA, HDMI, or DisplayPort output do support at least 16 and 32 bits per pixel (RGB565 and RGB888), and various output sizes/resolutions, usually configurable using VESA VCT timings (standard for CRTs, reduced for LCD panels).The order of the color components may vary, but that only matters when you are encoding specific colors. (For format conversion blitting, note that RGB565→RGB888 and BGR565→BGR888 do the exact same mapping. I do recommend having different functions for each mode tuple for rectangle conversion blitting, which also considers the rotations of the source and destination so that the larger pixel format is scanned in native order, for maximum cache locality; ignoring cacheline size considerations because the source and target are rarely perfectly cacheline aligned anyway.)Bits per pixel is only fixed for very limited devices likeauxdisplays(indrivers/auxdisplay/) which tend to have all display properties fixed. The graphics ones like old cfag12864b do provide a (very limited) framebuffer interface. (Nowadays you tend to see custom auxdisplay drivers very rarely and only in kernel forks ("Linux SDKs"), because current Linux SoCs tend to have built-in graphics cores with support similar to VGA/HDMI/DisplayPort outputting ones.)The reason for me to support both 16bpp and 32bpp is that many video devices use main RAM for the framebuffer, and at any given resolution, 16bpp needs half the RAM 32bpp does. Although some video devices have their own framebuffer RAM which cannot be easily used for other purposes, memory bandwidth on older devices is limited, and 16bpp can be significantly faster than 32bpp. Of course, 32bpp yields much better color reproduction and thus more pleasing visuals.To simplify, on smaller devices (say up to 7") I prefer 16bpp, and on larger ones, especially full-size displays, 32bpp. As an example, 800×480-16 = 768,000 bytes, but 800×480-32 = 1,536,000 bytes. If you only have 64M of RAM (sufficient to run minimal userspace with latest Linux kernels; it is the current minimum for e.g. OpenWRT), that is a significant difference.

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 28, 2025, 12:50:39 pm
content: Quote from: DiTBho on June 28, 2025, 09:46:54 amI do recommend reading back thefb_fix_screeninfoandfb_var_screeninfostructures (usingFBIOGET_FSCREENINFOandFBIOGET_VSCREENINFOioctls, respectively), after a successfulFBIOPUT_VSCREENINFOioctl, and verifying the settings arecompatible–– not that they are identical to what you requested, just that they are something you can support.The reason is precisely the same when using termios andtcsetattr(): the functions return success even if the new settings were only partially applied. (What it means for framebuffer devices, varies based on the framebuffer driver.) Things likefb_fix_screeninfo.line_lengthtends to require some hardware-specific alignment (usually a power of two, but the power varies!) –– it is set based on thefb_var_screeninfo.xres_virtualeven if you intend to do no panning at all, so to get a desirableline_lengthyou use the largestxres_virtualthat does not exceed the desiredline_length; the position of the red/green/blue components might differ slightly, and so on. Instead of the ioctl returning failure for every small detail, the drivers silently adjust minor details to the nearest supportable equivalent.

author: DiTBho
author_rank: Super Contributor
timestamp: June 30, 2025, 04:13:55 pm
content: Code:/** map fb to user mem** void* mmap* (* void* addr,* size_t length,* int prot,* int flags,* int fd,* off_t offset* );*/Code:fbfd = p_myscreen->fbfd;p_finfo = p_myscreen->p_finfo;prot = (PROT_READ | PROT_WRITE);len = p_finfo->smem_len; /* fb.stride * fb.height ?!? */fbp = mmap(NULL, len, prot, MAP_SHARED, fbfd, 0);/** On success, mmap() returns a pointer to the mapped area.* On error, the value MAP_FAILED (that is, p_err) is returned,* and errno is set to indicate the error.*/is_ok = (fbp isNotEqualTo p_err);if (is_ok isEqualTo False){fbp = NULL; /* myC needs NULL on Error */}p_myscreen->fbp = fbp;So, I open the "/dev/fb0" framebuffer (savagefb), try to set the color to 32 bits and then "mmap" it.MMap is a bit strange for me, when it fails it doesn't return NULL but (void *) -1, which in the case of "myC" cannot be expressed directly (casting is forbidden by the language), so you have to define p_err.Annoying, but it' not a problem, the code works ...... except that... when the bootloader loads the kernel, before entering it, it "maps" the framebuffer and something strange happens.The "logo" on the framebuffer disappears and the whole screen is replaced by an empty text consoleIt's empty, because it hasn't been associated with any virtual terminal.Why doesn't the framebuffer keep what the graphics mode draws on it?Is this a way to preserve the logo during kernel boot?I mean, without "embedding" the logo into the kernel.p.s.Code:len = p_finfo->smem_len; /* fb.stride * fb.height ?!? */This is a doubt that I haven't yet clarified, about which of the two is better.

author: DiTBho
author_rank: Super Contributor
timestamp: June 30, 2025, 05:25:36 pm
content: MAP_SHARED -> changes will be written back to the underlying fileMAP_PRIVATE -> you read the file into a private buffer, and other processes can still mmap the file, they just see it unmodified

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 30, 2025, 07:13:35 pm
content: Quote from: DiTBho on June 30, 2025, 04:13:55 pmAs I mentioned, I recommend usingmmap(NULL,len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fbfd, 0);. TheMAP_NORESERVEmeans the framebuffer is never swapped to disk. I use the same flags when I access existing files, too.In practice, it only matters if you get high memory pressure, and things start swapping.Quote from: DiTBho on June 30, 2025, 04:13:55 pmYeah. This is annoying. I wish there was a kernel command-line option to disable the clearing. It is trivial to add to most framebuffer drivers, though.See e.g.6.15.4/drivers/video/fbdev/savage/savagefb_driver.c:savage_map_video(), and the unconditionalmemset_io()at the end of that function. This is what clears the display. It is called from thesavagefb_driver.c:savage_probe(), which itself is called when the PCI device is detected (seesavagefb_driver.c:struct pci_driver savagefb_driver).All other framebuffer drivers end up doing something equivalent in their_probe()function, because traditionally the framebuffer was not cleared by BIOS and was full of semi-random garbage, often leftovers from initial BIOS text mode.Quote from: DiTBho on June 30, 2025, 04:13:55 pmFor true color and direct color, and even pseudocolor (indexed/paletted) modes I've seen,fb_fix_screeninfo.line_length == fb_var_screeninfo.bits_per_pixel*fb_var_screeninfo.xres_virtual.fb_fix_screeninfo.smem_len >= fb_var_screeninfo.bits_per_pixel*fb_var_screeninfo.xres_virtual*fb_var_screeninfo.yres_virtual,always.smem_lenis often larger on devices that have more dedicated RAM than can be used by the accelerator in the current graphics mode, and is the maximum amount of memory you can safely mmap on the device.Note that perLinux kernel Frame Buffer Library, each time you useFBIOPUT_VSCREENINFOsuccessfully,fb_fix_screeninfovalues will be reset too. If you only useFBIOGET_VSCREENINFOafterwards to check if the new settings are acceptable, use onlyfb_var_screeninfo.But, if you also useFBIOGET_FSCREENINFO, then usefb_fix_screeninfo.line_lengthforfb_ystride. If you want to store pre-prepared pixmaps, you can map all offb_fix_screeninfo.smem_len, and use everything not within the visible rectangle for offscreen buffers/caches/pixmaps.

author: DiTBho
author_rank: Super Contributor
timestamp: July 01, 2025, 11:36:41 pm
content: So, I added agetty to /dev/tty1 and the screen shows login and then /bin/bash correctly.Then, remotely, via ssh, I run my bootloader, which opens /dev/fb0, mmaps and displays the logo.Erm, the bootloader has a built-in shell, where you can issue commands and also type "exit" to end the bootloader, and this invokes fb_done, which in turn calls all the "done" methods.So, when it ends, it "un-mmap" and "fclose" /dev/fb0.And guess what? Before the bootloader is forced to exit, the screen displays the logo, but when it exits, it goes back to the text console, displaying exactly the same things as before the boot.And here I really don't understand, it seems that there are two graphics memories, one for the text console, which is saved when I invoke mmap, and one that uses mmap.Framebuffer memory should be just *one* memory, so if you do graphics on it, and then switch back to the text console, you should still have the graphics on the screenIn fact, you should clear the screen. Which is exactly what I do NOT want to do.

author: DiTBho
author_rank: Super Contributor
timestamp: July 01, 2025, 11:38:41 pm
content: Code:agetty -h -t 60 tty1 9600 vt100(nothing special)

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 02, 2025, 02:30:58 pm
content: Quote from: DiTBho on July 01, 2025, 11:36:41 pmThe contents of the Linux console terminal (text and attributes, not graphics data) are saved in kernel memory, and accessible via/dev/vcsN(text only) and/dev/vcsaN(text and attributes). This is what allows you to change the active terminal via keys orchvt, too.There are several possible options, depending on the exact behaviour you want.The best option to detach your application from the controlling terminal, open another tty (one not used by getty/mingetty/agetty etc.) as the new controlling terminal, and use the VT_ACTIVATE and VT_WAITACTIVE ioctls to switch to that console; seekbd/src/chvt.c(andkbd/src/libcommon/getfd.c) for details on how to do that.(You can also tell fbcon which console terminals are mapped to which framebuffer, if you have more than one framebuffer device, using Linux kernel command line options. SeeLinux fbcon documentationfor details.)In general, combining getty/mingetty/agetty with framebuffer application in the same console terminal with vgacon (CONFIG_VGA_CONSOLE) is complex, because vgacon will switch back to text mode. AFAIK, CONFIG_FRAMEBUFFER_CONSOLE does not change the mode, but getty/agetty/mingetty will clear the screen whenever it gets in control. The best option is to switch to a non-getty console.Quote from: DiTBho on July 01, 2025, 11:36:41 pmWell, it does not work that way in Linux, because of multiple console support (chvt or AltGr+F1..F12).

author: DiTBho
author_rank: Super Contributor
timestamp: July 02, 2025, 04:41:32 pm
content: And ... if I removed "fbcon" entirely? The bootloader doesn't need it, since it operates (the console is) on the serial.fbcon seems only causing problems.Umm, the second question is: I don't know the beavior of the kernel launched by exec().What will it do on the framebuffer? Will it immediately (as soon as video drivers is initialized) clear the screen for the earlyboot console?

author: DiTBho
author_rank: Super Contributor
timestamp: July 02, 2025, 11:07:20 pm
content: Quote from: Nominal Animal on July 02, 2025, 02:30:58 pmyup. In my case, for a diffeent project, the video card I an using for XINU/mips is a vhdl project made on the top of the "PCI MESA fpga card".It's one of those that have a physical PLX chip to manage the PCI transactions. Very old tecnology, modern ones come with Spartan6, and the PCI is completely managed by the fpga, which may sound cool but it adds a lot of complexity and vhdl code, and I don't like it.Anyway, I don't have more than 2Mbyte of SDRAM, dual port, on the card, and only 8Mbyte of ram on the SBC.Xinu eats 2Mbyte, including the filesystem and the network stack. Not so bad, but I only have 6Mbyte free for the applications.So I am using the video ram in a weird way.If the user application is in "graph mode", the whole video ram is managed as rgb555 framebuffer.If the user application is in "text mode", the video ram is split into chunks, addressing each pair of chunks as "text area and attribute area" for each terminal.chunk0 and chunk1 --> /dev/tty1chunk2 and chunk3 --> /dev/tty2....simpler designis rgb555 (15bpp) supported?!?it seems 18bpps is addressed as 24bpps, just with 6bit per color instead of 8.And ummm, I see the linux kenrel also mentions 1bit color? is it really supported? any hw example of this?

author: DiTBho
author_rank: Super Contributor
timestamp: July 02, 2025, 11:13:15 pm
content: What if I have or want to use a custom graphics card that can handle a 16-shade gray display(1)?What do you do with Linux? 8-bit color seems to be synonymous with "pseudo color"

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 03, 2025, 04:40:27 am
content: Quote from: DiTBho on July 02, 2025, 11:07:20 pmSome do.Others can support it via FB_VISUAL_DIRECTCOLOR, if one modifies the green mapping so that all even and odd entries have the same intensity; the lower one for the lower half entries, and the higher one for the upper half entries, and treat it as RGB565, but increment the green offset and decrement its length.If you just increment the green offset and decrement its length for RGB565, you'll get a very slight magenta tint, because then "white" is #FFFBFF (31,62,31) instead of #FFFFFF (31,63,31). In FB_VISUAL_DIRECTCOLOR, you have three ramps, one for each color component, usually used for gamma correction. But also works for RGB555 support.Quote from: DiTBho on July 02, 2025, 11:07:20 pmYes,Hercules graphics(old!) andcfag12864 auxdisplayfor example, probably many others. I don't know how many users/testers these have, so bit rot is a risk. In theory, it should work just fine.Quote from: DiTBho on July 02, 2025, 11:13:15 pmYou use FB_VISUAL_STATIC_PSEUDOCOLOR (or FB_VISUAL_PSEUDOCOLOR), with all three components having offset 0 and length 4. With FB_TYPE_PACKED_PIXELS, low nibbles are even pixels, and high nibbles odd pixels.Several framebuffer drivers support 4-bit (16-color) pseudocolor modes.

author: DiTBho
author_rank: Super Contributor
timestamp: July 03, 2025, 05:34:43 pm
content: Look at this picture!It's an old Apple laptop, G3 serie (early 2000s), running GNU/Linux Gentoo.The kernel is 2.6.26, nothing special, and you see a text terminal, fbcon, running "/usr/bin/top".But look at the background! There is a persistent graphical image as "background".How is it possible?How to achieve so?

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 03, 2025, 06:54:58 pm
content: Quote from: DiTBho on July 03, 2025, 05:34:43 pmWhich framebuffer driver? Is that actuallyfbterm, and not getty over fbcon? Or one of similar framebuffer virtual terminals? There are a few.To simplify a bit, getty on fbcon ≃ fbterm. You don't necessarily need to have fbcon to use fbterm, since one is not forced to run any getty's at all. (That is, you can replace getty with fbterm, and that only requires a framebuffer, not fbcon per se.)I checkedlinux-2.6.26/drivers/video/console/fbcon.c, and while fbcon can display the logo (usually Tux), even centered on-screen, I'm not sure if it keeps it on the background. I do know thatfbtermcan do that.

author: DiTBho
author_rank: Super Contributor
timestamp: July 03, 2025, 09:07:54 pm
content: Quote from: Nominal Animal on July 03, 2025, 06:54:58 pmIt's really getty over fbcon.I don't know what the trick is, but Yaboot includes an initrd file along with the kernel.What's in the initrd? I don't know, I haven't looked into it yetI found the kernel source code on the harddrive, the time stamp is about 2009, anyway it looks like Vanilla, nothing special with the ATIRage128 framebuffer kernel driver, fbcon or similar.

author: DiTBho
author_rank: Super Contributor
timestamp: July 03, 2025, 09:18:59 pm
content: Quote from: Nominal Animal on July 03, 2025, 06:54:58 pmI don't even understand how this is possible, the memory used for text terminals is separate from the memory used for graphics, so technically how does agetty on fbcon maintain a graphical background?I noticed something interesting today. If in a agetty fbcon I run my bootloader without cleaning the mmap memory during fb_init(), and without chaning the video mode (which probably internally invokes a clean method), I can draw something graphical in a corner, and it goes over the text.How is it possible?Quote from: Nominal Animal on July 03, 2025, 06:54:58 pmThere is no trace of "fbterm" on the hard disk

author: DiTBho
author_rank: Super Contributor
timestamp: July 03, 2025, 10:00:51 pm
content: Ummm, I think it wasfb-splashuserspace helpers and tools, using "Spoke's"fb-condecorkernel patches.Looks like a dead project, cannot find the old Spoke's blog anywhere, neither patches for kernel 2.6.It doesn't actually change the fbcon source, it adds other kernel modules.Anyway, I don't really understand how it works.It looks complex

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 03, 2025, 11:34:41 pm
content: (While I was writing this, I was reminded of your screen blanking issues on the terminal console. Do checkman 4 console_codesand specificallyprintf '\033[9;Xm\033[14;Xm', especially withXset to zero.)Quote from: DiTBho on July 03, 2025, 10:00:51 pmOh, it does; it adds the decor hooks to drivers/video/fbdev/core/fbcon.c.Quote from: DiTBho on July 03, 2025, 10:00:51 pmfbconis a kernel-side blitter, which renders the console terminal contents to the framebuffer. You can use kernel command line parameters to map specific consoles to specific framebuffer devices.fbtermis an old user-space framebuffer virtual terminal, that does the same thing in userspace.fbcondoes support display rotation, by blitting the characters rotated to the framebuffer. By default, it does not keep any kind of a background image, it just blits text with attributes to the framebuffer, and moves data around when scrolling, just like the Linux console terminal does. It is much more efficient ifCONFIG_FB_TILEBLITTINGis set. It uses hardware panning and wrapping if available, falling back to hardware 2D blitting, and tosoftware blittingif nothing else is available, so it should always be set.If you use getty for your terminal, then standard input, output, and error are directed to the/dev/ttyN. The kernel interprets the standard escape sequences, and keeps the terminal contents in/dev/vcsN(text only),/dev/vcsuN(Unicode glyphs), and/dev/vcsaN(text and attributes). Kernel console drivers like fbcon use ainclude/linux/console.h:struct conswto register a set of callbacks that the kernel terminal console uses to render them to any other backing.In userspace, fbterm and others can work in two different ways. One is to provide a virtual terminal (pseudoterminal pair), interpreting the escape sequences (listed inman 4 console_codes), and keeping the virtual terminal contents in its own buffers, rendering them however one wants. When used instead/as a getty, they read input from the terminal (because that's where they get the keyboard input), but might not use the terminal console for output at all.The other is to use the terminal console, but scan/dev/vcsuN(and optionally/dev/vcsaN) for changes, and updating any changes to the actual output device. The latter is used by screen readers and tools that mirror the terminal console contents to a separate device even when it is not active/foreground. (For example, you can do an X/Wayland application that displays their contents as a read-only window. It will need elevated privileges to access the/dev/vcsaNand/dev/vcsuN, however.If one wanted to layer text and framebuffer contents to the actual display device, one option would be to create an fbcon derivative that also provides a synthetic framebuffer device (seeauxdisplay framebuffer driversfor simple implementations), using say 16-bit ZRGB1555 format, with Z=0 shown beneath the text, and Z=1 above the text. While the console terminal does have support for 24-bit RGB color (just try it:printf '\033[38;2;255;204;153mThis is #FFCC99.\033[0m\n'), it does not have an escape code to define RGBA, so the only way to define the opacities of the 16 standard colors is to use theFBIOPUTCMAP/FBIOGETCMAPioctl on the framebuffer device, which is a bit oddish.Then, the derivative kernel module would composite the currently active console terminal (if any) with the synthetic framebuffer data, to the actual framebuffer device.The downside is the extra memory use, and the slowness. A 1024×768 ZRGB1555 takes 1.5MBytes, and compositing the display contents with say a 8×12 fixed font (128×64 text window) takes its own lookup tables to do efficiently. Some hardware can do something similar by themselves, of course.If you have read this far, you'll now have a good idea why one of my hobby projects is a small IPS display panel "controller" that internally composites 3-4 such framebuffer layers; one full-color background one, and 3-4 indexed color (pseudocolor, 4-bit or 8-bit pixels, a 256-entry ARGB palette per layer). It just opens up so many newshenanigans. Well,oldones, because that what was made arcade and early home game consoles so visually powerful when processors and microprocessors just didn't have the grunt we have available today. Doing it in software is somewhat taxing, so shortcuts and optimizations are quite important for performance. I haven't tried implementing it as a pixel shader for OpenGL ES or similar, but I do believe it would be possible; on any Linux SBC with Mali or other supported OpenGL ES implementation the GPU hardware would do it once per display update (60 - 70 times per second).

author: DiTBho
author_rank: Super Contributor
timestamp: July 04, 2025, 08:04:34 am
content: I was a bit confused by what i found on the harddrive: /user/src/kernel/kernel-2.6.26 looks like a fresh vanillaProbably genkernel or something else was used, which copied those sources to a temporary directory where patches were then appliedhowever, "lspatch" leaves no doubt, here are the files that are modified by one of the most recent patchesCode:# lspatch fbcondecor-5.10.patchlinux-5.10/Documentation/fb/fbcondecor.txtlinux-5.10/drivers/Makefilelinux-5.10/drivers/video/console/Kconfiglinux-5.10/drivers/video/console/Makefilelinux-5.10/drivers/video/console/cfbcondecor.clinux-5.10/drivers/video/console/fbcondecor.clinux-5.10/drivers/video/console/fbcondecor.hlinux-5.10/drivers/video/fbdev/Kconfiglinux-5.10/drivers/video/fbdev/core/bitblit.clinux-5.10/drivers/video/fbdev/core/fbcmap.clinux-5.10/drivers/video/fbdev/core/fbcon.clinux-5.10/drivers/video/fbdev/core/fbmem.clinux-5.10/include/linux/console_decor.hlinux-5.10/include/linux/console_struct.hlinux-5.10/include/linux/fb.hlinux-5.10/include/uapi/linux/fb.hlinux-5.10/kernel/sysctl.c

author: DiTBho
author_rank: Super Contributor
timestamp: July 04, 2025, 08:45:00 am
content: (that is, to understand, the laptop in the photo is mineMany years ago, I lent it to a CCC event,and it was returned to me all modified and hackedI haven't used it for about 10 years)

author: DiTBho
author_rank: Super Contributor
timestamp: July 04, 2025, 09:03:45 am
content: Quote from: Nominal Animal on July 03, 2025, 11:34:41 pmI 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.

author: DiTBho
author_rank: Super Contributor
timestamp: July 09, 2025, 11:55:14 pm
content: 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 640x480How to change it without invoking external program like "fbset"?Code: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.

author: DiTBho
author_rank: Super Contributor
timestamp: July 10, 2025, 10:11:54 pm
content: Tempted to replicate "fbset", embedding into my code.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 11, 2025, 02:12:22 pm
content: Quote from: DiTBho on July 09, 2025, 11:55:14 pmYou useFBIOPUT_VSCREENINFOwith timing fields (.pixclock,.{left,right,upper,lower}_margin,.sync_len,.sync,.vmode) filled withcoordinated video timings(with reduced blanking, if using LCD panels) matching.xresand.yres.

author: DiTBho
author_rank: Super Contributor
timestamp: July 11, 2025, 08:47:30 pm
content: I have these valuesCode:mode "240x320"# D: 7.428 MHz# H: 22.787 kHz# V: 70.547 Hzgeometry 240 320 240 320 16timings 134617 20 46 1 0 20 2endmodemode "480x640"# D: 51.999 MHz# H: 75.252 kHz# V: 116.851 Hzgeometry 480 640 480 640 16timings 19231 46 125 1 0 40 3endmodeLCD pannel, PXAfb driven

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 13, 2025, 03:44:29 pm
content: Givenfbsetor/etc/fb.modesmode withgeometryxresyresvxresvyres16timingspixclockleftrightupperlowerhslenvslenthe correspondingstruct fb_var_screeninfofields 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_TESTfirst to only test if the values are acceptable, the driver rounding up any incompatible settings.

author: DiTBho
author_rank: Super Contributor
timestamp: July 13, 2025, 05:17:59 pm
content: I'm seeing strange things.bpp=32bit, RGB888 works perfectly on all my tested machinesOn 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 fineCode: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: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

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 13, 2025, 09:37:48 pm
content: You do need to do a followupFBIOGET_VSCREENINFOto get the actual.red,.green,.blue, and.transpvalues. TheFBIOSET_VSCREENINFOwith.activate = FB_ACTIVATE_NOWdoesnotmodify 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 },

author: DiTBho
author_rank: Super Contributor
timestamp: July 14, 2025, 06:13:02 pm
content: It seems it's RGB565, it works perfectly with savagefb, but something is wrong with the radeonfbsee ...Code:fb_init() on /dev/fb0Switching to 16 ... successfb_do_geometry0(): 1440 960 16fb_angle_handler() angle=0fb_angle_handler_000() bipp=16sizeof(rgba[])={ 5 6 5 (0) }offset(rgba[])={ 11 5 0 (0) }...(radeonfb)Code:.../** read vinfo*/io = (ioctl(fbfd, FBIOGET_VSCREENINFO, p_vinfo));is_ok = (io isEqualTo 0);.../** how many bit?*/rgb = p_vinfo->red.length;rgb = p_vinfo->green.length;rgb = p_vinfo->blue.length;rgb = p_vinfo->transp.length;.../** offset?*/rgb = p_vinfo->red.offset;rgb = p_vinfo->green.offset;rgb = p_vinfo->blue.offset;rgb = p_vinfo->transp.offset;...(32bpp, rgb888, radeonfb)(16bpp, rgb565, radeonfb)

author: DiTBho
author_rank: Super Contributor
timestamp: July 14, 2025, 06:23:20 pm
content: ATI Radeon 9700, 128 MByte Video ramCode:fb_init() on /dev/fb0Switching to 16 ... successfb_do_geometry0(): 1440 960 16fb_angle_handler() angle=0fb_angle_handler_000() bipp=16sizeof(rgba[])={ 5 6 5 (0) }offset(rgba[])={ 11 5 0 (0) }(radeonfb, 16bpp)Code:fb_init() on /dev/fb0Switching to 32 ... successfb_do_geometry0(): 1440 960 32fb_angle_handler() angle=0fb_angle_handler_000() bipp=32sizeof(rgba[])={ 8 8 8 (0) }offset(rgba[])={ 16 8 0 (0) }(radeonfb, 32bpp)

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 14, 2025, 10:27:16 pm
content: One possible solution would be to use a variant of a/etc/fb.modesconfiguration file that names supported modes including RGB color components.For example, you could useDebianfbsetformat, withrgbRlen/RoffGlen/GoffBlen/Boff[Tlen/Toff]to define the color component locations, ignoring thestruct fb_var_screeninfostructure.You can do a very lightweight parser by consuming input one token at a time. Formode,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. Forrgb, you need to get the nextlengthorlength/offsetpair (withoffsetdefaulting to zero), only skipping leading whitespace. For the rest, you need to get the next token expected to betrue/yes/high/1 orfalse/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.

author: DiTBho
author_rank: Super Contributor
timestamp: July 14, 2025, 10:43:52 pm
content: 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.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 14, 2025, 11:44:22 pm
content: Quote from: DiTBho on July 14, 2025, 10:43:52 pmNo, but ever since KMS/DRI came along, the actual framebuffer drivers have very few users, and radeonfb in particular has changed a lot between2.6.39.4and6.15.6.I suspect the underlying issue isdrivers/gpu/drm/drm_fourcc.c:drm_mode_legacy_fb_format(16, 15or16), since the issue is thatstruct fb_var_screeninfogets.red,.green,.bluefilled in perDRM_FORMAT_RGB565but the actual mode usesDRM_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_formatvalue used in e.g.v5.4.229/drivers/gpu/drm/radeon/atombios_crtc.c:dce4_crtc_do_set_base()orv5.4.229/drivers/gpu/drm/radeon/atombios_crtc.c:avivo_crtc_do_set_base(). In both cases, the effective value isfb_format=0<<8(XRGB1555), with thefb_var_screeninfoadvertising values corresponding tofb_format=1<<8(RGB565). To me, this indicates that there is some issue in setting the correctfb_formatvalue in one of the aforementioned functions, so that "effectively"fb_format==0is 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_FOURCCis nonzero.)

author: DiTBho
author_rank: Super Contributor
timestamp: July 15, 2025, 09:30:01 pm
content: Quote from: Nominal Animal on July 14, 2025, 11:44:22 pmThe "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.

author: DiTBho
author_rank: Super Contributor
timestamp: July 15, 2025, 09:42:03 pm
content: 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 terminalI bought several PCI cardsI 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

author: DiTBho
author_rank: Super Contributor
timestamp: July 15, 2025, 09:47:35 pm
content: Quote from: Nominal Animal on July 14, 2025, 11:44:22 pmFrom 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.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 17, 2025, 07:42:20 pm
content: 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 valuesgandg+32.Component gamma curves are almost always programmable, but whether they are exposed via Linux framebufferFBIOPUTCMAPioctl does vary. If supported, the parameter is a pointer tostruct fb_cmap.You 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.redand.bluehaving the actual ramp in indexes 0..31 and repeating it for 32..64 (but most drivers do not use the upper copy), and the.greendepends 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.transpis optional.

author: DiTBho
author_rank: Super Contributor
timestamp: July 17, 2025, 08:57:35 pm
content: Quote from: Nominal Animal on July 17, 2025, 07:42:20 pmbuilt-in kernel driver, radeonfb, it's not the DRM-based version.

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 18, 2025, 01:18:12 am
content: Okay, so the key kernel source file isv2.6.26.8/drivers/video/aty/radeonfb.h,v2.6.26.8/drivers/video/aty/atyfb_base.c, andv2.6.26.8/drivers/video/aty/radeon_base.c.The comment inradeon_base.c:radeonfb_check_var()indicates the driver only supports8-bit grayscale,ARGB555(ignoring \$a_0\$),RGB565, andARGB888(ignoring \$a_0\$ through \$a_7\$). Because these values are what you see instruct fb_var_screeninfobut 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 bykernel 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. TheFBIOPUTCMAPioctl invokesv2.6.26/drivers/video/fbmem.c:fb_ioctl(), which ends up callingv2.6.26/drivers/video/fbcmap.c:fb_set_user_cmap(), which ends up callingv2.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 isv2.6.26/drivers/video/aty/aty128fb.c:aty128fb_setcolreg(), on Radeons it isv2.6.26/drivers/video/aty/radeon_base.c:radeonfb_setcmap(), and on other ATi GPUs, it isv2.6.26/source/drivers/video/aty/atyfb_base.c:atyfb_setcolreg()(where the comment is incorrect: suppliedred,green, andbluevalues 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 useFBIOPUTCMAPwith astruct fb_cmapthat has.start = 0,.len = 64,.transp = NULL, the 32 initial entries in.redand.bluecontaining the gamma ramp from0x0000to0xFFFF, inclusive, same repeated for the latter 32 entries, and all 64 entries in.greendefining the green ramp, also mapped to0x0000..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.greenare the same they are for.redand.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 theFBIOPUTCMAPwith 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-entrystruct fb_cmapwhere each color ramp repeats four times. Then, your 16-bit pixel colors are0bWrrrrXYggggZbbbbin binary, whereW,X,Y, andZare the unused bits. They are not contiguous and cannot be contiguous using standard Linux framebuffer userspace interface, unfortunately, unlike inARGB444orRGBA4444modes.(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).)

author: DiTBho
author_rank: Super Contributor
timestamp: July 18, 2025, 09:56:23 pm
content: Code:# fb_bpp 16Switching to 16 bpp ... successtrying rgb_8888 ... failuretrying rgb_0888 ... failuretrying rgb_0565 ... failuretrying rgb_1555 ... failuretrying rgb_0555 ... successfb_angle_handler() angle=0fb_angle_handler_000() bipp=16setting intersposing handlers ... successI implemented a new command to "probe" bpp/rgb-color.It seems the aty128fb supports 16bpp rgb0555Code:# uname -r2.6.26-wombat-apple-powerbook-G4-pismocolors are perfect

author: Nominal Animal
author_rank: Super Contributor
timestamp: July 19, 2025, 12:40:30 am
content: 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 matchsRGB, 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 effectivefb_var_screeninfostructures 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 theFBIOPAN_DISPLAYioctl. (It takes a pointer to astruct fb_var_screeninfo, wherexoffsetandyoffsetset the visible area within the virtual framebuffer; thev2.6.26/drivers/video/fbmem.c:fb_pan_display()handles the ioctl, and uses the per-framebufferfb_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_VBLto auto-delay the operation until the next vertical blanking interval, I recommend using aFBIO_WAITFORVSYNCioctl with the argument pointing to anintset to zero, followed byFBIOPAN_DISPLAYwith updatedxoffset/yoffsetmembers andactivate=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.