Upto: Table of Contents of full book "Programming the Raspberry Pi GPU"

Dispmanx on the Raspberry Pi

Dispmanx is the lowest level of programming the RPi's GPU. We don't go very deeply into it, just enough to get a native window for use by other toolkits.

Resources

Accessing the GPU

The lowest level of accessing the GPU seems to be by an API called Dispmanx. Now people don't write their graphics applications using Dispmanx. Instead, they use Dispmanx to get a window that is then used by a framework such as EGL and from there by OpenGLES.

Just to give you total lack of encouragement from using Dispmanx there are hardly any examples and no serious documentation. However, that hasn't stopped AndrewFromMelbourne from developing a set of programs such as drawing Mandelbrot figures, animating triangles, etc. I'm not going to delve deeply into his programs - you can download them from raspidmx if you want.

We just use Dispmanx to get some information about the display size and then to create a window that takes up the full screen. We don't do anything else in this chapter - this is just a building block on the way to using the Dispmanx window within a higher-level API. If you want, explore AndrewFromMelbourne's examples.

The relevant Dispmanx calls to build a window are

	
    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;

   success = graphics_get_display_size(0 /* LCD */, 
             &screen_width, &screen_height);
    assert( success >= 0 );

    dst_rect.x = 0;
    dst_rect.y = 0;
    dst_rect.width = screen_width;
    dst_rect.height = screen_height;

    src_rect.x = 0;
    src_rect.y = 0;
    src_rect.width = screen_width << 16;
    src_rect.height = screen_height << 16;        

    dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
    dispman_update = vc_dispmanx_update_start( 0 );
    dispman_element = 
        vc_dispmanx_element_add(dispman_update, dispman_display,
                                0/*layer*/, &dst_rect, 0/*src*/,
                                &src_rect, DISPMANX_PROTECTION_NONE, 
                                0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
	
      

At the end of this you have a window stored in dispman_element that can be used as a native window object later.

The complete program is info.c and just prints the size of the screen:

	 /*
 * code stolen from openGL-RPi-tutorial-master/encode_OGL/
 */

#include <stdio.h>
#include <assert.h>
//#include <math.h>
#include <bcm_host.h>
//#include <vc_dispmanx.h>
//#include <vc_dispmanx_types.h>

//#include <EGL/egl.h>
//#include <EGL/eglext.h>
//#include <GLES2/gl2.h>

typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
} DISPMANX_STATE_T;

DISPMANX_STATE_T state, *p_state = &state;

void init_dispmanx(DISPMANX_STATE_T *state) {
    int32_t success = 0;

    bcm_host_init();

    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;

    success = graphics_get_display_size(0 /* LCD */, 
					&state->screen_width, 
					&state->screen_height);
    assert( success >= 0 );

    printf("Screen height %d, width %d\n",
	   state->screen_height, state->screen_width);

    dst_rect.x = 0;
    dst_rect.y = 0;
    dst_rect.width = state->screen_width;
    dst_rect.height = state->screen_height;

    src_rect.x = 0;
    src_rect.y = 0;
    src_rect.width = state->screen_width << 16;
    src_rect.height = state->screen_height << 16;        

    state->dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
    dispman_update = vc_dispmanx_update_start( 0 );

    dispman_element = 
	vc_dispmanx_element_add(dispman_update, state->dispman_display,
				0/*layer*/, &dst_rect, 0/*src*/,
				&src_rect, DISPMANX_PROTECTION_NONE, 
				0 /*alpha*/, 0/*clamp*/, 0/*transform*/);

    /* Now we have created a native Dispmanx window
     * Toolkits such as OpenGL ES will use this for
     * their own 'native window' type, with code like this:

    static EGL_DISPMANX_WINDOW_T nativewindow;

    nativewindow.element = dispman_element;
    nativewindow.width = state->screen_width;
    nativewindow.height = state->screen_height;
    vc_dispmanx_update_submit_sync( dispman_update );
    assert(vc_dispmanx_element_remove(dispman_update, dispman_element) == 0);
    */
}

int
main(int argc, char *argv[])
{
    init_dispmanx(p_state);

    assert( vc_dispmanx_display_close(p_state->dispman_display) == 0);

    return 0;
}


      

A Makefile to build this is

	
DMX_INC =  -I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux

INCLUDES = $(DMX_INC)

CFLAGS = $(INCLUDES)
CPPFLAGS = -march=armv7-a -mtune=cortex-a7

DMX_LIBS =  -L/opt/vc/lib/ -lbcm_host -lvcos -lvchiq_arm -lpthread
LDFLAGS =  $(DMX_LIBS)

all: info
	
      

It can then be run easily by

	
./info
	
      

Garbage collection

C does not have automatic garbage collection like Java or other languages have. You have to do it yourself. This program does little else apart from open a display. This can be closed by vc_dispmanx_display_close(p_state->dispman_display). it doesn't actually seem to make a difference, but is tidier anyway.

Showing free memory of RAM used by the CPU is common: tools such as top give a good idea, with ps drilling down deeper. To show the memory used by the GPU is more tricky, and there is a Broadcom tool vcdbg to show that. Even if nothing has been run, it shows some memory usage (with 512M of RAM devoted to the GPU):

	
$/opt/vc/lib /opt/vc/bin/vcdbg reloc

Relocatable heap version 4 found at 0x1f000000
total space allocated is 492M, with 492M relocatable, 0 legacy and 0 offline
0 legacy blocks of size 2359296

free list at 0x3d886520
489M free memory in 1 free block(s)
largest free block is 489M bytes

0x1f000000: free 489M
[   4] 0x3d886540: used  576 (refcount 1 lock count 0, size      512, align    4, data 0x3d886560, d0rual) 'ILCS VC buffer pool'
[   3] 0x3d886780: used 3.5M (refcount 1 lock count 8, size  3618816, align 4096, data 0x3d887000, d1rual) 'ARM FB'
[   2] 0x3dbfafa0: used  16K (refcount 1 lock count 0, size    16384, align   32, data 0x3dbfafc0, d0ruAl) 'audioplus_tmp_buf'
[   1] 0x3dbfefe0: used 4.0K (refcount 1 lock count 0, size        0, align 4096, data 0x3dbff000, d1rual) 'camera fast alloc arena'
small allocs not requested
	
      

Screen capture

Andrew from Melbourne has written a program using Dispmanx called raspi2png to capture the RPi screen and save it as a PNG file. The source code demonstrates additional Dispmanx calls.

Conclusion

Dispmanx is the layer between EGL and the Broadcom GPU. We just looked at enough to supply that bridge.

	
      

Copyright © Jan Newmarch, jan@newmarch.name
Creative Commons License
" Programming AudioVideo on the Raspberry Pi GPU " by Jan Newmarch is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .
Based on a work at https://jan.newmarch.name/RPi/ .

If you like this book, please contribute using PayPal

Or Flattr me:
Flattr this book