mark_3094
Posts: 74
Joined: Mon Jul 02, 2012 8:38 am
Location: Australia

Virtual Frame Buffer

Mon Jun 17, 2013 12:06 pm

I'm interested in learning more about the virtual framebuffer (although I don't know much about graphics theory).
In the frame buffer structure, there are some fields relating to virtual width, virtual height, x and y offset.

I've read in a few places (including some replies to an old post of mine http://www.raspberrypi.org/phpBB3/viewt ... 6&p=264141) that to improve performace, the virtual framebuffer can be set to twice the size of the physical framebuffer (eg, if the physical screen is 800x600, set the virtual to 800*1200), which creates a physcial and a virtual screen.

I think the offset can then be used to 'flip' between these screens, so the background buffer can be updated, then 'flipped' over onto the physical screen.

Is this correct? If so, other than setting the virtual height in the framebuffer structure, how is this implemented? What 'flips' these buffers, and is it really faster than writing directly to the framebuffer?

If there's already some good information or tutorials out there, please let me know (I've had a look, but I can't find much).
Thankyou for your help

GeneraV
Posts: 31
Joined: Mon Feb 04, 2013 2:10 am

Re: Virtual Frame Buffer

Wed Jun 19, 2013 7:50 pm

Hi
I use this

Code: Select all

InitVSync:                      stmfd sp!, {r0-r1, lr}
                                move r0, 0x2000B214
                                move r1, 0x00010000
                                str r1, [r0]
                                move r0, 0x20600000
                                mov r1, 0
                                str r1, [r0]
  .Exit:                        ldmfd sp!, {r0-r1, pc}

FlipScreen:                     ;;; Enter with:-
                                ;;;   Nothing
                                ;;; Leave with:-
                                ;;;   r12=Pointer to screen buffer to write to.
                                stmfd sp!, {r0-r5, lr}
                                move r0, FrameBufferStructure
                                ldr r1, [r0, 28]
                                cmp r1, 0
                                beq .SetDisplayHigherHalf
  .SetDisplayLowerHalf:         mov r1, 0
                                b .Continue
  .SetDisplayHigherHalf:        ldr r1, [r0, 4]
  .Continue:                    str r1, [r0, 28]
                                b SetScreen.ByPassEntry

SetScreen:                      stmfd sp!, {r0-r5, lr}
  .ByPassEntry:                 move r0, 0x2000B208
  .LoopVSync:                   ldr r1, [r0]
                                tst r1, 0x00010000
                                beq .LoopVSync

                                ;;; Tell GPU about FrameBuffer structure
  .MailWriteLoop:               move r1, PERIPHERAL_BASE + MAIL_BASE + MAIL_STATUS
                                ldr r0, [r1]
                                and r0, r0, MAIL_FULL
                                cmp r0, MAIL_FULL
                                beq .MailWriteLoop
                                ;bl SmallDelay
                                move r0, FrameBufferStructure+BUS_ADDRESSES_l2CACHE_ENABLED
                                orr r0, r0, 1
                                move r1, PERIPHERAL_BASE + MAIL_BASE + MAIL_WRITE + MAIL_FB
                                str r0, [r1]
                                ;bl SmallDelay
                                ;;; See if GPU knows about required frame buffer structure
  .MailReadLoop:                move r1, PERIPHERAL_BASE + MAIL_BASE + MAIL_STATUS
                                ldr r0, [r1]
                                and r0, r0, MAIL_EMPTY
                                cmp r0, MAIL_EMPTY
                                beq .MailReadLoop
                                ;bl SmallDelay
                                move r1, PERIPHERAL_BASE + MAIL_BASE + MAIL_READ
                                ldr r0, [r1]
                                mov r3, 0
                                and r0, r0, 0xf
                                cmp r0, MAIL_FB
                                bne .MailReadLoop
                                and r3, r3, 0xFFFFFFF0
                                cmp r3, 0
                                bne .MailWriteLoop
                                move r0, FrameBufferStructure.ScreenPointer ;FRAME_BUFFER_ADDRESS+0x20;0xa00020
                                ldr r0, [r0]
                                cmp r0, 0
                                beq .MailWriteLoop
                                move r0, FrameBufferStructure
                                ldr r1, [r0, 28]
                                ldr r12, [r0, 32]
                                cmp r1, 0
                                beq .SetPointerHighHalf
  .SetPointerLowHalf:           b .Exit
  .SetPointerHighHalf:          move r1, (SCREEN_WIDTH*SCREEN_HEIGHT*4)
                                add r12, r1
  .Exit:                        ldmfd sp!, {r0-r5, pc}


align 16
FrameBufferStructure:
  .PhysicalWidth:               dw SCREEN_WIDTH     ;;; 0
  .PhysicalHeight:              dw SCREEN_HEIGHT    ;;; 4
  .VirtualWidth:                dw SCREEN_WIDTH     ;;; 8
  .VirtualHeight:               dw SCREEN_HEIGHT*2  ;;; 12
  .Pitch:                       dw 0                ;;; 16
  .BitDepth:                    dw SCREEN_BIT_DEPTH ;;; 20
  .DisplayXOffset:              dw 0                ;;; 24
  .DisplayYOffset:              dw 0                ;;; 28
  .ScreenPointer:               dw 0                ;;; 32
  .ScreenFrameSize:             dw 0                ;;; 36
With the following macro-

Code: Select all

macro move reg,immediate {
      mov reg,(immediate) and $FF
      orr reg,(immediate) and $FF00
      orr reg,(immediate) and $FF0000
      orr reg,(immediate) and $FF000000
}
Now I use in my kernel.asm

Code: Select all

bl InitVSync
          bl SetScreen
which returns the graphic area to be written in R12 the use FlipScreen to display the backbuffer!

mark_3094
Posts: 74
Joined: Mon Jul 02, 2012 8:38 am
Location: Australia

Re: Virtual Frame Buffer

Fri Jun 21, 2013 8:18 am

I'm not great with ARM assembly yet, but it looks like you're trying to do this:

1. Set the virtual framebuffer to twice the size of the physical screen (vertically) in the structure
2. Call 'vsync' - I don't understand this yet
3. Use 'setscreen' to setup the framebuffer (using the mailbox)
4. Check if the Y offset is upper or lower half of the framebuffer. Update the pointer offset accordingly (to write to either the top or bottom half of the virtual framebuffer)

Then it looks like you have 'flipscreen' to alternate between the top and bottom half.
Is this right so far?

Is one of the buffer's 'active', meaning it's contents are displayed on the screen, while the other is the one I should write to? Then, when I've finished writing to the 'passive' buffer, I can 'flip' it, and it becomes what is seen on the screen?


Thanks again for your help.

mark_3094
Posts: 74
Joined: Mon Jul 02, 2012 8:38 am
Location: Australia

Re: Virtual Frame Buffer

Sat Jul 06, 2013 4:30 am

One more thought...
I've read that I can output to screen faster by using DMA. How does this work?
Is it because DMA makes copying between the physical and virtual framebuffer faster?

Are there any tutorials out there on implementing DMA on baremetal?

GeneraV
Posts: 31
Joined: Mon Feb 04, 2013 2:10 am

Re: Virtual Frame Buffer

Sun Jul 07, 2013 5:42 pm

Hi
Sorry for not responding quickly, sometimes life gets in the way! DMA moves memory around independent of the CPU. It's that simple. Have a look at this (under 'helloworld') https://github.com/PeterLemon/RaspberryPi
Now in your config.txt you need the following entry for the vsync to work

Code: Select all

fake_vsync_isr=1
Hopes this helps :D

mark_3094
Posts: 74
Joined: Mon Jul 02, 2012 8:38 am
Location: Australia

Re: Virtual Frame Buffer

Tue Jul 09, 2013 4:26 am

Thanks, I'll have a look and see what I can do :)

Return to “Bare metal, Assembly language”