I have run it up, and actually I'm not going to debug that in detail. Having to run as sudo in order to mmap random chunks of /dev/mem is too nasty.
vc_dispmanx_resource_get_image_handle does return a bus address pointer to the VC_IMAGE_T *.
get_dispmanx_resource_mem gives you the mem_handle from that structure directly. You don't actually need the rest of the VC_IMAGE_T *.
mem_lock gives you a bus address for the image data buffer (NOT the VC_IMAGE_T*).
mapmem should be able to map that and you can write to it.
Code: Select all
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// A simple demo using dispmanx to display an overlay
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
#include "bcm_host.h"
// New includes and defines
#include "mailbox.h"
#include "interface/vctypes/vc_image_structs.h"
typedef VC_IMAGE_T VC_IMAGE_BUF_T;
#define BUS_TO_PHYS(x) ((x)&~0xC0000000)
#define WIDTH 200
#define HEIGHT 200
#ifndef ALIGN_UP
#define ALIGN_UP(x,y) ((x + (y)-1) & ~((y)-1))
#endif
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;
static void FillRect( VC_IMAGE_TYPE_T type, void *image, int pitch, int aligned_height, int x, int y, int w, int h, int val )
{
int row;
int col;
uint16_t *line = (uint16_t *)image + y * (pitch>>1) + x;
for ( row = 0; row < h; row++ )
{
for ( col = 0; col < w; col++ )
{
line[col] = val;
}
line += (pitch>>1);
}
}
int main(void)
{
RECT_VARS_T *vars;
uint32_t screen = 0;
int ret;
VC_RECT_T src_rect;
VC_RECT_T dst_rect;
VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565;
// New variables ...
int fd;
VC_IMAGE_T* pImage;
uint32_t memHandle;
uint32_t addr;
int width = WIDTH, height = HEIGHT;
int pitch = ALIGN_UP(width*2, 32);
int aligned_height = ALIGN_UP(height, 16);
VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
120, /*alpha 0->255*/
0 };
vars = &gRectVars;
bcm_host_init();
printf("Open display[%i]...\n", screen );
vars->display = vc_dispmanx_display_open( screen );
ret = vc_dispmanx_display_get_info( vars->display, &vars->info);
assert(ret == 0);
printf( "Display is %d x %d\n", vars->info.width, vars->info.height );
vars->image = calloc( 1, pitch * height );
assert(vars->image);
memset(vars->image, 0xFF, pitch*height);
vars->resource = vc_dispmanx_resource_create( type,
width,
height,
&vars->vc_image_ptr );
assert( vars->resource );
vc_dispmanx_rect_set( &dst_rect, 0, 0, width, height);
ret = vc_dispmanx_resource_write_data( vars->resource,
type,
pitch,
vars->image,
&dst_rect );
assert( ret == 0 );
vars->update = vc_dispmanx_update_start( 10 );
assert( vars->update );
vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 );
vc_dispmanx_rect_set( &dst_rect, ( vars->info.width - width ) / 2,
( vars->info.height - height ) / 2,
width,
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 );
ret = vc_dispmanx_update_submit_sync( vars->update );
assert( ret == 0 );
// New code to try get raw pointer to resource pixel data
// Based on some notes from Herman Hermitage and this link:
// http://blog.eihis.com/2015/07/03/raspberry-pi-dispmanx-resources-and-videocore-gpu-hacks/
fd = mbox_open();
//pImage = vc_dispmanx_resource_get_image_handle( vars->resource ); // This call is supposed to return a ptr to a VC_IMAGE_T struct in GPU mem..
// In theory, it has a mem_handle field, but given this returned address you cannot directly access it, not sure if it should be mem mapped first?
// with something like:
// VC_IMAGE_T* pImage2 = (VC_IMAGE_T*)mapmem(BUS_TO_PHYS(pImage), sizeof(VC_IMAGE_T));
// printf("VC_IMAGE_T %ux%u format %u, memhandle %u\n", pImage->width, pImage->height, pImage->type, pImage->mem_handle );
memHandle = get_dispmanx_resource_mem(fd, vars->resource); // Use the mailbox to get a pointer to the resource as per: https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
printf("memhandle %u\n", memHandle );
addr = mem_lock(fd, memHandle); // Lock the gpu handle, should return a pointer. NB Physical/bus address
printf("addr %x\n", addr );
unsigned char* pImageData = (unsigned char*)mapmem(BUS_TO_PHYS(addr), pitch*height);
if (pImageData)
{
sleep(4);
FillRect( type, pImageData, pitch, aligned_height, 0, 0, width, height, 0xFFFF );
sleep(1);
FillRect( type, pImageData, pitch, aligned_height, 0, 0, width, height, 0xF800 );
sleep(1);
FillRect( type, pImageData, pitch, aligned_height, 20, 20, width - 40, height - 40, 0x07E0 );
sleep(1);
FillRect( type, pImageData, pitch, aligned_height, 40, 40, width - 80, height - 80, 0x001F );
sleep(1);
// memset(pImageData, 0xff, 100); // write something into the pixel data
unmapmem(pImageData, pitch*height);
}
mem_unlock(fd, memHandle); // unlock gpu mem handle
mbox_close(fd); // close mailbox
printf( "Sleeping for 4 seconds...\n" );
sleep( 4 );
vars->update = vc_dispmanx_update_start( 10 );
assert( vars->update );
ret = vc_dispmanx_element_remove( vars->update, vars->element );
assert( ret == 0 );
ret = vc_dispmanx_update_submit_sync( vars->update );
assert( ret == 0 );
ret = vc_dispmanx_resource_delete( vars->resource );
assert( ret == 0 );
ret = vc_dispmanx_display_close( vars->display );
assert( ret == 0 );
return 0;
}
I've rearranged a couple of blocks so the resource is put on the screen before mmaping. You can then see that it is directly writing the live buffer as the writes for red, green, and blue are done. Yes, that could tear.
Pass as to the caching options in this path. As you are unmapping almost immediately I would expect that to flush but can't guarantee it.
I'm not pushing that back to github as others may then take that as a good example, and it really isn't.