2

I'm wondering if the following is possible: I would like to display a test pattern on my Raspberry Pi and then clear it while going back to the original display. Thanks Low-Level Graphics on the Raspberry Pi, writing into the Frame Buffer is easy. What I'm not sure about is stopping updates from other sources and refreshing the Frame Buffer after I'm done.

I think this is relatively easy if the RPi is just displaying a terminal. I can disable the prompt and draw my test pattern. On exit, I can blank the screen and enable the prompt. I don't know how to handle this when LXDE is running (or how to tell which mode I'm in). Can I stop displaying cursor updates and then force a full screen refresh?

Thanks!

Update

Thanks to Krzysztof Adamski's help, I'm close to a complete answer. While running LXDE, I can draw a test pattern to the frame buffer and it will not be overwritten as long as I turn off the CPU utilization monitor and as long as I don't move the mouse. When I want to remove the test pattern, I can call DISPLAY=:0 xrefresh -black to "refresh" the screen (i.e. redraw the GUI in its current state). Now I just need to find a way to temporarily disable input devices.

By the way, this project is really just a way to remotely display test patterns so I can check out the monitor/TV. I'll be showing it to people and I know they're going to move the mouse while the test pattern is up. Had to say something because I realized the project was starting to sound kind of nefarious. :)

2 Answers 2

2

Thanks to everyone that helped. I thought I would post my final solution to help others that might read this question. It's basically the code from dispmanx with a few of the things that I learned.

First, in order to compile you will need to add the following include directories to your makefile

+= /opt/vc/include
+= /opt/vc/include/interface/vcos/pthreads

and the following library.

-Lopt/vc/lib/ -lbcm_host

Now include the "bcm_host.h" file in your source and the following structure definition:

typedef struct
{
    DISPMANX_DISPLAY_HANDLE_T   display;
    DISPMANX_MODEINFO_T         info;
    void                        *image;
    DISPMANX_UPDATE_HANDLE_T    update;
    DISPMANX_RESOURCE_HANDLE_T  resource;
    DISPMANX_ELEMENT_HANDLE_T   element;
    uint32_t                    vc_image_ptr;

} RECT_VARS_T;

static RECT_VARS_T gRectVars = { 0 };

When the program starts, call the bcm_host_init() function to initialize the video core.

My goal was to display full screen, solid color test patterns. I simplified down the dispmanx example and moved the FillRect function code into the following source. I realize my current method to generate the test pattern is not optimal in terms of performance, but I left it in case I add more complicated test patterns in the future (us565RGB is the color pattern).

RECT_VARS_T *vars;
VC_RECT_T src_rect;
VC_RECT_T dst_rect;
VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
                          255, /*alpha 0->255*/
                          0 };

vars = &gRectVars;
vars->display = vc_dispmanx_display_open( 0 );
vc_dispmanx_display_get_info( vars->display, &vars->info);

vars->image = calloc( 1, vars->info.width * vars->info.height * 2);

/* Construct the test pattern */
uint16_t *line = (uint16_t *) vars->image;
for ( int row = 0; row < vars->info.height; row++ )
{
    for ( int col = 0; col < vars->info.width; col++ )
    {
        line[col] = us565RGB;
    }
    line += vars->info.width;
}

vars->resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565,
                                              vars->info.width,
                                              vars->info.height,
                                              &vars->vc_image_ptr );

vc_dispmanx_rect_set( &dst_rect, 0, 0, vars->info.width, vars->info.height);

vc_dispmanx_resource_write_data( vars->resource,
                                 VC_IMAGE_RGB565,
                                 vars->info.width * 2,
                                 vars->image,
                                 &dst_rect );

vars->update = vc_dispmanx_update_start( 10 );

vc_dispmanx_rect_set( &src_rect, 0, 0, vars->info.width << 16, vars->info.height << 16 );
vc_dispmanx_rect_set( &dst_rect, 0, 0, vars->info.width, vars->info.height );

vars->element = vc_dispmanx_element_add( vars->update,
                                         vars->display,
                                         2000, // layer
                                         &dst_rect,
                                         vars->resource,
                                         &src_rect,
                                         DISPMANX_PROTECTION_NONE,
                                         &alpha,
                                         NULL, // clamp
                                         VC_IMAGE_ROT0 );

vc_dispmanx_update_submit_sync( vars->update ); 

To clear the test pattern, I call the following code:

  if ( gRectVars.image != NULL )
  {
    gRectVars.update = vc_dispmanx_update_start( 10 );
    vc_dispmanx_element_remove( gRectVars.update, gRectVars.element );
    vc_dispmanx_update_submit_sync( gRectVars.update );
    vc_dispmanx_resource_delete( gRectVars.resource );
    vc_dispmanx_display_close( gRectVars.display );

    memset( &gRectVars, 0x00, sizeof( RECT_VARS_T ) );
  }

Finally, I've observed that you do not want to call the code that creates a test pattern without clearing the previous test pattern. If you do, the previous test pattern will be "stuck" on the display and the only way to remove it appears to be rebooting the Raspberry Pi. You also don't want to exit the program without clearing the test pattern because, again, it will leave the test pattern on the display and a reboot appears to be the only way to fix it. Unfortunately clearing the test pattern and switching to another one means you'll see the first pattern, then the live display (command prompt or GUI), and then the next test pattern. I experimented a bit with modifying the active test pattern, but abandoned that effort due to time and the lack of documentation on the API.

Hope this helps!

0
1

Direct answer

You can't do this reliably since there is no framebuffer arbiter or anything like that. This means you can't stop X server from writing to framebuffer after you displayed your pattern. If nobody moves cursor/windows and no program is currently drawing some animation, it shouldn't happen. You can also rewrite the screen couple times a second to prevent your content to be overwritten by X (unless you have some animation happening in which case X server will be doing the same.

You can read the framebuffer content at the beginning of your program and write it back when you finishes, restoring the screen but this may not be up to date. You can also force X server to refresh the screen (xrefresh command from x11-xserver-utils does this) but I'm not sure how it's done. You have to check the sources. It probably uses some xlib or xcb function for this.

Other aproach

While I found this problem to be interesting, I'm still actually not sure why can't you just write X application that will open on full screen instead of manually writing to framebuffer. If you care about being able to run also without X, you should investigate SDL library. It should be very easy to write such application for example using python and pygame (but you can of course use any other language with SDL support).

9
  • xrefresh definitely seems like half of the answer! One problem is that I can't run it over SSH or from the command line because I get a "unable to open display'' " error. Apr 18, 2013 at 18:46
  • 1
    try setting environment variable DISPLAY before running it. For example DISPLAY=:0 xrefresh. X server should be already running, of course. Apr 18, 2013 at 19:19
  • You may also be interested in temporarily disabling X screensaver while you are displaying your test pattern. Apr 18, 2013 at 19:28
  • 1
    Thanks, using DISPLAY=:0 xrefesh works. I did find quite a bit of information on disabling the screensaver when I was first digging into the problem. Unfortunately for me it seemed like most people wanted to boot to a blank screen and then make sure a screensaver never started. Different enough from my goal that I was still left with questions. Apr 18, 2013 at 20:10
  • 3
    You can use dispmanx API (github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/…) to put layer above all windows; then draw on that layer.
    – kolontsov
    Apr 19, 2013 at 6:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.