AnthonyPaulO
Posts: 28
Joined: Fri Aug 11, 2017 1:07 pm

Simple VGA Mode X (direct frame buffer) programming

Fri Aug 11, 2017 3:38 pm

Back in the day I used to do some VGA (mode X) programming on the IBM; I would now like to do the same type of retro-style graphics (perhaps upgrade a bit to Super VGA) in order to display graphics for an emulator I'm writing but not sure where to start. I'm aware that the Pi folks released their gpu libraries as open source to userland (https://github.com/raspberrypi/userland) but I don't need OpenGL or any of those fancy shmancy interfaces (or do I?) so I'm wondering if someone can point me to the right guide; I just want some good ol' fashioned writing to video memory if I can have it.

Many thanks in advance,

Anthony

dwelch67
Posts: 824
Joined: Sat May 26, 2012 5:32 pm

Re: Simple VGA Mode X (direct frame buffer) programming

Sat Aug 12, 2017 2:28 am

Yeah, even easier than that, you do a handshake or two with the gpu to gain access to a framebuffer, then you just poke bytes in to draw pixels, as simple as mode x was. Already in these forums are a number of discussions on getting the framebuffer address, not as complicated as folks make it out (didnt need so many discussions) you setup a structure kick the right mailbox and get your answer and start drawing pixels.

I did it once years ago, I do everything with the uart, and dont bother with video/graphics so am not the first person to ask on the details, having had done it, it was pretty easy back then, not sure if the pi2 or pi3 adds any complication but there are a number of folks here with bare metal code that can point you at their examples or work the details...

User avatar
rpdom
Posts: 11521
Joined: Sun May 06, 2012 5:17 am
Location: Essex, UK

Re: Simple VGA Mode X (direct frame buffer) programming

Sat Aug 12, 2017 6:20 am

I agree, once you have worked out how to set up a frame buffer it is easy to poke pixels. I've only done it on a Pi 1, but I wrote a simple emulation of the BBC Micro's MODE 7 display with blinking text and flashing cursor (at different rates) by using timers and interrupts.

colinh
Posts: 94
Joined: Tue Dec 03, 2013 11:59 pm
Location: Munich

Re: Simple VGA Mode X (direct frame buffer) programming

Sun Aug 13, 2017 12:22 am

For the Raspberry Pi 2:

Code: Select all

// Mailbox_base (Baking Pi/Screen01)
//.set MBX_base,            0x2000B880		// for RPi Model B
.set MBX_base,              0x3F00B880
.set MBX_READ,              0x00000000
.set MBX_POLL,              0x00000010
.set MBX_SNDR,              0x00000014
.set MBX_STAT,              0x00000018
.set MBX_CONF,              0x0000001C
.set MBX_WRITE,             0x00000020


.globl init_framebuffer
init_framebuffer:          // r0, r1 = requested x,y resolution

    push    {lr}

    ldr r2, =fb_info            // description of requested buffer
    str r0, [r2, #0]
    str r1, [r2, #4]
    str r0, [r2, #8]
    str r1, [r2, #12]

    ldr r1, =MBX_base
1:
    ldr r0, [r1, #MBX_STAT]
    tst r0, #0x80000000         // ready to write?
    bne 1b
//  add r2, #0x40000000         // flag for unbuffered memory (for RPi Model B)
    add r2, #0xC0000000 
    add r2, #1                  // MBX channel 1
    str r2, [r1, #MBX_WRITE]    // write to mailbox

1:
    ldr     r0, [r1, #MBX_STAT]
    tst     r0, #0x40000000         // ready to read?
    bne     1b
    ldr     r0, [r1, #MBX_READ]
    and     r2, r0, #0b1111         // bits[3:0] are channel, [31:4] message
    teq     r2, #1                  // MBX channel 1
    bne     1b                      // repeat until we've read channel 1
    bics    r0, #0b1111             // clear channel bits. What's left should be 0
    bne     slow_flash              // signals error

    ldr r2, =fb_info
    ldr r0, [r2, #32]
    and r0, #0x3FFFFFFF	// turn the FB ptr into a proper address // NOT FOR RPi Mod B
    str r0, [r2, #32]

    pop {pc}

.section .data

.align 5

.globl fb_info
fb_info:
    .int 1920   // 00 width
    .int 1080   // 04 height
    .int 1920   // 08 v_width
    .int 1080   // 0C v_height
    .int 0      // 10 FB-bytes per line (gets filled in by GPU)
    .int 16     // 14 bit depth
    .int 0      // 18 X offset
    .int 0      // 1C Y offset
    .int 0      // 20  FB-Pointer (gets filled in by GPU)
    .int 0      // 24 FB-Size (gets filled in by GPU)
    .word 0xFFFFFFFF    // end marker
This won't compile - unless you have a routine named "slow_flash". Put your own error handling code there.

Also, I've hard-coded the bit depth to be 16 bits per pixel (RGB=5:6:5).

Google "Baking Pi Screen 01" for explanations (and slightly different code).

LdB
Posts: 539
Joined: Wed Dec 07, 2016 2:29 pm

Re: Simple VGA Mode X (direct frame buffer) programming

Sun Aug 13, 2017 3:26 am

Your code has a small bug which we all had for a while because we all generally started from the same tutorials which do it.

When you are writing to the mailbox the check for full status should be offset 0x38 .. not 0x18 which is the read status and fortunately will be clear which is why the code works.

Rst can take the credit for being the first to notice we were all doing it wrong and provided code that proved it.
viewtopic.php?t=165529&p=1068619

On the Pi3 there are a couple of places it becomes important because the mailbox can actually get full.

The bug exists in a great many Pi code repo's out there and it's going to take some effort to get rid of.

So you need
.set MBX_WR_STAT, 0x00000038

And the first status read in you code needs to be to it.

User avatar
ab1jx
Posts: 361
Joined: Thu Sep 26, 2013 1:54 pm
Location: Heath, MA USA
Contact: Website

Re: Simple VGA Mode X (direct frame buffer) programming

Sun Aug 13, 2017 1:48 pm

Interesting to see this in assembly, I had only seen the mailbox stuff in the context of /opt/vc/src/hello_pi/hello_fft/mailbox.c.

And framebuffer stuff in the Raspberry Compote context of opening /dev/fb0 then using mmap http://raspberrycompote.blogspot.com/20 ... _9509.html Very slow.

So I've been using libvncserver to get a virtual framebuffer that's more portable. I'm guessing that once you've connected and have your pointer one framebuffer is pretty much the same as another from a graphics standpoint. The assembly method is no doubt fastest but probably doesn't work over VNC because it doesn't go through XOrg. If you need it to work over VNC try libvncserver. You could write your programs so they switch from one to the other on a keystroke by switching pointers.

But on common ground, is there any off-the-shelf widget set available that works with framebuffers? I'm interested in buttons with text labels mostly. I've made some primitive boxes and code to detect when a mouse click happens inside them.

colinh
Posts: 94
Joined: Tue Dec 03, 2013 11:59 pm
Location: Munich

Re: Simple VGA Mode X (direct frame buffer) programming

Sun Aug 13, 2017 2:16 pm

LdB wrote:
Sun Aug 13, 2017 3:26 am
Your code has a small bug which we all had for a while because we all generally started from the same tutorials which do it.

[...]

Rst can take the credit for being the first to notice we were all doing it wrong and provided code that proved it.
viewtopic.php?t=165529&p=1068619
Oh, thanks! That's really interesting.
On the Pi3 there are a couple of places it becomes important because the mailbox can actually get full.
And that's particularly useful, thanks!

User avatar
RichardUK
Posts: 220
Joined: Fri Jun 01, 2012 5:12 pm

Re: Simple VGA Mode X (direct frame buffer) programming

Sat Sep 02, 2017 9:31 pm

I just used this old tutorial to give me a leg up. :-)

The PI seems to now boot to 32bpp in this tutorial they say it boots to 16bpp. Using my RPi zero the code to switch too 8bit pallet mode works too. The closest you'll get to Mode X.

Mode X was cool, writing to 4 pixels at once (had to be the same colour) and copying vram to vram for fast blits. :D

User avatar
ab1jx
Posts: 361
Joined: Thu Sep 26, 2013 1:54 pm
Location: Heath, MA USA
Contact: Website

Re: Simple VGA Mode X (direct frame buffer) programming

Sat Sep 02, 2017 11:29 pm

RichardUK wrote:
Sat Sep 02, 2017 9:31 pm
I just used this old tutorial to give me a leg up. :-)
The Compote article, I started with that. But as my program got more complicated it got slower and more buggy. I think getting a pointer by using the mailbox is probably the way to go rather than using /dev/fb0. I was also on a Pi 3 rather than whatever it was written for. I remember screen clears with a loop took several seconds.

But not being able to use widgets like pushbuttons and text boxes were the deciding factor since I need those. In a few environments like QT and Java Swing there are framebuffer widets which coexist on the screen with widgets like pushbuttons, but I couldn't find one for GTK.

Then I went back to plain XLib like I was doing last winter at viewtopic.php?f=33&t=174679&p=1115186#p1115186. That XDrawLine() is fast and efficient, I can update my screen several times per second at something like 30% CPU usage. My latest screenshot of my SDR program:
Image

The spectrum is drawn using XDrawLine from one point to the next, the waterfall uses XCopyArea to provide downward scrolling. Lately I've been floundering in Motif tutorials because most widgets are actually windows, hence drawables. Instead of creating a blank window on the root window I should be able to draw to a widget, and have pushbuttons, etc. around it. I think I'm about to go to Glade, Motif tutorials are old and I have trouble getting most to compile.

Actually this one isn't bad: https://www.smnd.sk/anino/programming/X ... motif.html All the examples compile and work, some need to have a #include <stdio.h> and/or #include <stdlib.h> added.

Return to “Bare metal”

Who is online

Users browsing this forum: No registered users and 2 guests