int Initialize() { fbfd = 0; fbp = 0; setlogmask(LOG_UPTO(LOG_DEBUG)); openlog("fbcp", LOG_NDELAY | LOG_PID, LOG_USER); bcm_host_init(); display = vc_dispmanx_display_open(0); if (!display) { syslog(LOG_ERR, "Unable to open primary display"); return -1; } ret = vc_dispmanx_display_get_info(display, &display_info); if (ret) { syslog(LOG_ERR, "Unable to get primary display information"); return -1; } syslog(LOG_INFO, "Primary display is %d x %d", display_info.width, display_info.height); fbfd = open("/dev/fb1", O_RDWR); if (!fbfd) { syslog(LOG_ERR, "Unable to open secondary display"); return -1; } if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { syslog(LOG_ERR, "Unable to get secondary display information"); return -1; } if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { syslog(LOG_ERR, "Unable to get secondary display information"); return -1; } syslog(LOG_INFO, "Second display is %d x %d %dbps\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt); if (!screen_resource) { syslog(LOG_ERR, "Unable to create screen buffer"); close(fbfd); vc_dispmanx_display_close(display); return -1; } fbp = (char*) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if (fbp <= 0) { syslog(LOG_ERR, "Unable to create mamory mapping"); close(fbfd); ret = vc_dispmanx_resource_delete(screen_resource); vc_dispmanx_display_close(display); return -1; } vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres); return 1; }
void save_snapshot(void) { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T info; DISPMANX_RESOURCE_HANDLE_T resource; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888; VC_IMAGE_TRANSFORM_T transform = 0; VC_RECT_T rect; void *image; uint32_t vc_image_ptr; int ret; uint32_t screen = 0; fprintf(stderr,"\nWriting snapshot...\n"); //fprintf(stderr,"Open display[%i]...\n", screen ); display = vc_dispmanx_display_open( screen ); ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); //fprintf(stderr,"Display is %d x %d\n", info.width, info.height ); image = calloc( 1, info.width * 3 * info.height ); assert(image); resource = vc_dispmanx_resource_create(type, info.width, info.height,&vc_image_ptr); vc_dispmanx_snapshot(display, resource, transform); vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); vc_dispmanx_resource_read_data(resource, &rect, image, info.width*3); char* home = getenv("HOME"); char filename[1024]; if (!home) home = "/tmp"; snprintf(filename,sizeof(filename),"%s/pidvbip-%u.ppm",home,(unsigned int)time(NULL)); FILE *fp = fopen(filename, "wb"); fprintf(fp, "P6\n%d %d\n255\n", info.width, info.height); fwrite(image, info.width*3*info.height, 1, fp); fclose(fp); fprintf(stderr,"\nSnapshot written to %s\n",filename); ret = vc_dispmanx_resource_delete( resource ); assert( ret == 0 ); ret = vc_dispmanx_display_close(display ); assert( ret == 0 ); free(image); }
int main(void) { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T info; DISPMANX_RESOURCE_HANDLE_T resource; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888; VC_IMAGE_TRANSFORM_T transform = 0; VC_RECT_T rect; void *image; uint32_t vc_image_ptr; int ret; uint32_t screen = 0; bcm_host_init(); printf("Open display[%i]...\n", screen ); display = vc_dispmanx_display_open( screen ); ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); printf( "Display is %d x %d\n", info.width, info.height ); image = calloc( 1, info.width * 3 * info.height ); assert(image); resource = vc_dispmanx_resource_create( type, info.width, info.height, &vc_image_ptr ); vc_dispmanx_snapshot(display, resource, transform); vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); vc_dispmanx_resource_read_data(resource, &rect, image, info.width*3); FILE *fp = fopen("out.ppm", "wb"); fprintf(fp, "P6\n%d %d\n255\n", info.width, info.height); fwrite(image, info.width*3*info.height, 1, fp); fclose(fp); ret = vc_dispmanx_resource_delete( resource ); assert( ret == 0 ); ret = vc_dispmanx_display_close(display ); assert( ret == 0 ); return 0; }
//------------------------------------------------------------------------------ // bool OsdGraphics::Init() { uint32_t screen = 0; printf("Open display[%i]...\n", screen ); m_Display = vc_dispmanx_display_open( screen ); if (vc_dispmanx_display_get_info( m_Display, &m_Info)) { std::cout << "OsdGraphics::Init: vc_dispmanx_display_get_info failed" << std::endl; return(false); } printf( "Display is %d x %d\n", m_Info.width, m_Info.height ); }
void vo_open(RECT_VARS_T* vars, int screen) { int ret; /* Init from dispmanx.c */ DEBUGF("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); DEBUGF( "Display is %d x %d\n", vars->info.width, vars->info.height ); /* End of dispmanx.c init */ }
void dispmanxtest() { DISPMANX_DISPLAY_HANDLE_T display; int ret; DISPMANX_MODEINFO_T displayinfo; DISPMANX_RESOURCE_HANDLE_T res; int width = 1024; int height = 576; uint32_t vc_image_ptr; DISPMANX_UPDATE_HANDLE_T update; VC_RECT_T dst_rect,src_rect; DISPMANX_ELEMENT_HANDLE_T element; bcm_host_init(); display = vc_dispmanx_display_open(0); ret = vc_dispmanx_display_get_info( display, &displayinfo); assert(ret==0); printf("display is %dx%d\n",displayinfo.width,displayinfo.height); res = vc_dispmanx_resource_create(VC_IMAGE_YUV420,width,height,&vc_image_ptr); vc_image_ptr = vc_dispmanx_resource_get_image_handle(res); printf("vc_image_ptr %x\n",vc_image_ptr); assert(res); update = vc_dispmanx_update_start(10); assert(update); vc_dispmanx_rect_set(&src_rect,0,0,width<<16,height<<16); vc_dispmanx_rect_set(&dst_rect,0,(displayinfo.height - height)/2,width-32,height); element = vc_dispmanx_element_add(update,display,2000,&dst_rect,res,&src_rect,DISPMANX_PROTECTION_NONE,NULL,NULL,DISPMANX_NO_ROTATE); ret = vc_dispmanx_update_submit_sync(update); assert(ret==0); uint8_t *rawfb = (uint8_t*)mapmem(vc_image_ptr,0x1000); for (int i=0; i<0x100; i++) { printf("%02x ",rawfb[i]); } printf("\n"); unmapmem(rawfb,0x1000); puts("sleeping"); sleep(10); update = vc_dispmanx_update_start(10); assert(update); ret = vc_dispmanx_element_remove(update,element); assert(ret==0); ret = vc_dispmanx_update_submit_sync(update); assert(ret==0); ret = vc_dispmanx_resource_delete(res); assert(ret==0); ret = vc_dispmanx_display_close(display); assert(ret==0); }
void CRBP::GetDisplaySize(int &width, int &height) { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T info; display = vc_dispmanx_display_open( 0 /*screen*/ ); if (vc_dispmanx_display_get_info(display, &info) == 0) { width = info.width; height = info.height; } else { width = 0; height = 0; } vc_dispmanx_display_close(display ); }
SliceMngr::SliceMngr(){ int result; uint16_t background = 0x000F; DISPMANX_UPDATE_HANDLE_T update; mState = 0; bcm_host_init(); mDisplay = vc_dispmanx_display_open(0); if(mDisplay == 0){ return; } result = vc_dispmanx_display_get_info(mDisplay, &mInfo); if(result != 0){ return; } initBackgroundLayer(&mBackground, background, 1); initImage(&(mImage.image), VC_IMAGE_RGBA32, mInfo.width, mInfo.height, false); createResourceImageLayer(&mImage, 0); vc_dispmanx_rect_set(&(mImage.srcRect), 0 << 16, 0 << 16, mImage.image.width << 16, mImage.image.height << 16); vc_dispmanx_rect_set(&(mImage.dstRect), (mInfo.width - mImage.image.width) / 2, (mInfo.height - mImage.image.height) / 2, mImage.image.width, mImage.image.height); update = vc_dispmanx_update_start(0); if(update == 0){ return; } addElementBackgroundLayer(&mBackground, mDisplay, update); addElementImageLayerCentered(&mImage, &mInfo, mDisplay, update); result = vc_dispmanx_update_submit_sync(update); if(result != 0){ return; } mState = 1; }
int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *width, uint32_t *height) { DISPMANX_DISPLAY_HANDLE_T display_handle = 0; DISPMANX_MODEINFO_T mode_info; int32_t success = -1; if (display_handle == 0) { // Display must be opened first. display_handle = vc_dispmanx_display_open(display_number); vcos_assert(display_handle); } if (display_handle) { success = vc_dispmanx_display_get_info(display_handle, &mode_info); if( success >= 0 ) { if( NULL != width ) { *width = mode_info.width; } if( NULL != height ) { *height = mode_info.height; } } } if ( display_handle ) { vc_dispmanx_display_close(display_handle); display_handle = 0; } return success; }
int main(int argc, char *argv[]) { int quality = 75; if (argc == 2) { quality = atoi(argv[1]); if (quality < 10 || quality > 100) { fprintf(stderr, "invalid quality. must be between 10 and 100\n"); return 1; } } bcm_host_init(); uint32_t screen = 0; DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(screen); DISPMANX_MODEINFO_T info; int ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); /* DispmanX expects buffer rows to be aligned to a 32 bit boundary */ int pitch = ALIGN_UP(2 * info.width, 32); uint32_t vc_image_ptr; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565; DISPMANX_RESOURCE_HANDLE_T resource = vc_dispmanx_resource_create( type, info.width, info.height, &vc_image_ptr ); VC_IMAGE_TRANSFORM_T transform = 0; vc_dispmanx_snapshot(display, resource, transform); VC_RECT_T rect; vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); unsigned char *image = malloc(pitch * info.height); assert(image); vc_dispmanx_resource_read_data(resource, &rect, image, info.width * 2); ret = vc_dispmanx_resource_delete(resource); assert(ret == 0); ret = vc_dispmanx_display_close(display); assert(ret == 0); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, stdout); cinfo.image_width = info.width; cinfo.image_height = info.height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); int row_stride = cinfo.image_width * 3; while (cinfo.next_scanline < cinfo.image_height) { unsigned char row[row_stride]; unsigned char *dst = &row[0]; uint16_t *src = (uint16_t*)(image + pitch * cinfo.next_scanline); for (int x = 0; x < cinfo.image_width; x++, src++) { *dst++ = ((*src & 0xf800) >> 11) << 3; *dst++ = ((*src & 0x07e0) >> 5) << 2; *dst++ = ((*src & 0x001f) >> 0) << 3; } row_pointer[0] = row; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); return 0; }
static SDL_Surface *DISPMANX_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags) { //MAC Recuerda que aqui,originalmente, nos llegaban las dimensiones de un modo de video // aproximado en SDL_Video.c de entre los modos de video disponibles. AHORA YA NO. //Ahora lo que hacemos es que nos lleguen directamente la altura y anchura del modo //en el que quiere correr la aplicacion, //Luego se escala ese modo, de cuanta menos resolucion mejor, (ya que hay //que hacer una escritura de ram a grafica en la funcion FlipHWScreen), al modo fisico, que //es en realidad el unico modo grafico que existe, el modo en que hemos arrancado. //Esto explica por que creamos el plano de overlay a parte, //ya que cuando SDL_Video.c llama a SetVideoMode aun no se tienen listos los //offsets horizontal y vertical donde empieza el modo de video pequenio //(el modo en que corre la app internamente) sobre el grande (el modo fisico). //Si nos pasan width=0 y height=0, interpreto que el programa no quiere video sino //que solo necesita entrar en modo grafico, asi que salto alli: if ((width == 0) | (height == 0)) goto go_video_console; //MAC Inicializamos el SOC (bcm_host_init) SOLO si no hemos pasado antes por aqui. Lo mismo con el fondo. //Si ya hemos pasado antes, hacemos limpieza, pero dejamos el fondo sin tocar. if (dispvars->pixmem != NULL){ //Hacemos limpieza de resources, pero dejamos el fondo. No hay problema porque solo lo ponemos //si no hemos pasado por aqui antes. DISPMANX_FreeResources(); } else { uint32_t screen = 0; bcm_host_init(); //MAC Abrimos el display dispmanx printf("Dispmanx: Opening display %i\n", screen ); dispvars->display = vc_dispmanx_display_open( screen ); //MAC Recuperamos algunos datos de la configuracion del buffer actual vc_dispmanx_display_get_info( dispvars->display, &(dispvars->amode)); printf( "Dispmanx: Physical video mode is %d x %d\n", dispvars->amode.width, dispvars->amode.height ); //Ponemos el element de fondo negro tanto si se respeta el ratio como si no, //porque si no, se nos veraa la consola al cambiar de resolucion durante el programa. DISPMANX_BlankBackground(); } //-------Bloque de lista de resoluciones, originalmente en VideoInit-------------- //Para la aplicacion SDL, el unico modo de video disponible va a ser siempre el que pida. DISPMANX_AddMode(this, width, height, (((bpp+7)/8)-1)); //--------------------------------------------------------------------------------- Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; //dispvars->pitch = width * ((bpp+7) /8); //MAC Establecemos el pitch en funcion del bpp deseado //Lo alineamos a 16 porque es el aligment interno de dispmanx(en ejemp) dispvars->bits_per_pixel = bpp; dispvars->pitch = ( ALIGN_UP( width, 16 ) * (bpp/8) ); //Alineamos la atura a 16 por el mismo motivo (ver ejemplo hello_disp) height = ALIGN_UP( height, 16); switch (bpp){ case 8: dispvars->pix_format = VC_IMAGE_8BPP; break; case 16: dispvars->pix_format = VC_IMAGE_RGB565; break; case 32: dispvars->pix_format = VC_IMAGE_XRGB8888; break; default: printf ("\n[ERROR] - wrong bpp: %d\n",bpp); return (NULL); } //MAC blah this->UpdateRects = DISPMANX_DirectUpdate; printf ("\nUsing internal program mode: %d x %d %d bpp", width, height, dispvars->bits_per_pixel); //MAC Por ahora en DISPMANX usamos el mismo modo q ya esta establecido printf ("\nUsing physical mode: %d x %d %d bpp", dispvars->amode.width, dispvars->amode.height, dispvars->bits_per_pixel); //----------------------------------------------------------------------------- //Esta parte no es fundamental, solo sirve para conservar el ratio del juego. //Si no se hace y simplemente quitas estas lineas, se estira al modo fisico y ya, //quedando la imagen deformada si es de 4:3 en una tele de 16:9, que es lo que pasaba antes. //Simplemente hallamos ese ratio y con el hallamos la nueva anchura, considerando //como altura la maxima fisica que tenemos establecida, o sea, la altura del modo fisico establecido. //Tambien se calcula la posicion horizontal en que debe empezar el rect de destino (dst_ypos), //para que no quede pegado a la parte izquierda de la pantalla al ser menor que la resolucion fisica, que //obviamente no cambia. //Queda obsoleto si cambiamos la resolucion a una que tenga el mismo ratio que el modo original del juego. dispvars->ignore_ratio = (int) SDL_getenv("SDL_DISPMANX_IGNORE_RATIO"); if (dispvars->ignore_ratio) vc_dispmanx_rect_set( &(dispvars->dst_rect), 0, 0, dispvars->amode.width , dispvars->amode.height ); else { float orig_ratio = ((float)width / (float)height); int dst_width = dispvars->amode.height * orig_ratio; //Si la anchura de la imagen escalada nos sale mayor que el ancho fisico de pantalla, //mantenemos el ancho fisico de pantalla como anchura maxima. if (dst_width > dispvars->amode.width) dst_width = dispvars->amode.width; int dst_ypos = (dispvars->amode.width - dst_width) / 2; printf ("\nUsing proportion ratio: %d / %d = %f", width, height, orig_ratio); printf ("\nProgram rect, respecting original ratio: %d x %d \n", dst_width, dispvars->amode.height); vc_dispmanx_rect_set( &(dispvars->dst_rect), dst_ypos, 0, dst_width , dispvars->amode.height ); } //---------------------------Dejamos configurados los rects--------------------- //Recuerda que los rects NO contienen ninguna informacion visual, solo son tamanio, rectangulos //descritos para que los entiendan las funciones vc, solo tamanios de areas. // //bmp_rect: se usa solo para el volcado del buffer en RAM al resource que toque. Define el tamanio //del area a copiar de RAM (pixmem) al resource (dispmam->resources[]) usando write_data(), por //eso, y para acabarlo de entender del todo, su altura y anchura son las internas del juego, width y height. // //src_rect y dst_rect: se usan porque un element necesita dos rects definidos: src_rect es el tamanio del area //de entrada,o sea, el tamanio con el que clipeamos la imagen de origen, y dst_rect es el tamanio del area de //salida, o sea, el tamanio con que se vera, escalada por hardware, en el element. // //Por todo esto, src_rect tendra generalmente la altura y anchura de la imagen original, o dicho de otro //modo la altura y anchura que usa el juego internamente (width << 16 y height << 16 por algun rollo de //tamanio de variable), y dst_rect tendra las dimensiones del area de pantalla a la que queremos escalar //esa imagen: si le damos las dimensiones fisicas totales de la pantalla, escalara sin respetar el ratio. //Asique lo he corregido manteniendo la altura maxima de la pantalla fisica, y calculando la anchura //a partir de dicha altura y el ratio de la imagen (de la resolucion del juego) original. // //Debes pensar siempre de la siguiente manera: un element, que es como un cristal-lupa, un resource //(aunque tengas dos, en un momento dado el element solo tiene uno) que es como la imagen original, //muy pequenita al fondo, y un "embudo", cuyo tamanio del extremo inferior pegado a la imagen original //es de tamanio src_rect, y cuyo tamanio del extremo superior, pegado al element, es de tamanio dst_rect. vc_dispmanx_rect_set (&(dispvars->bmp_rect), 0, 0, width, height); vc_dispmanx_rect_set (&(dispvars->src_rect), 0, 0, width << 16, height << 16); //------------------------------------------------------------------------------ //MAC Establecemos alpha. Para transparencia descomentar flags con or. VC_DISPMANX_ALPHA_T layerAlpha; /*layerAlpha.flags = (DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS);*/ layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; layerAlpha.opacity = 255; layerAlpha.mask = 0; dispvars->alpha = &layerAlpha; //MAC Creo los resources. Me hacen falta dos para el double buffering dispvars->resources[0] = vc_dispmanx_resource_create( dispvars->pix_format, width, height, &(dispvars->vc_image_ptr) ); dispvars->resources[1] = vc_dispmanx_resource_create( dispvars->pix_format, width, height, &(dispvars->vc_image_ptr) ); //Reservo memoria para el array de pixles en RAM dispvars->pixmem = calloc( 1, dispvars->pitch * height); //dispvars->pixmem=malloc ( dispvars->pitch * dispvars->amode.height ); //MAC Esta llamada a ReallocFormat es lo que impediaa ver algo... Rmask = 0; Gmask = 0; Bmask = 0; if ( ! SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, 0) ) { return(NULL); } //Preparamos SDL para trabajar sobre el nuevo framebuffer //No queremos HWSURFACEs por la manera en que funciona nuestro backend, ya que la app solo //debe conocer el buffer en RAM para que las actualizaciones no sean bloqueantes. //TAMPOCO queremos DOUBLEBUFFER: realmente piensa lo que estas haciendo: actualizas la //superficie de video, que esta en la RAM, copias a VRAM y, saltandote las normas del API, //esperas a evento de vsync para hacer el buffer swapping. Asi que la app NO SABE NADA de //double buffering ni debe saberlo. UpdateRect() debe hacer lo que antes haciaa FlipHWSurface, //ya que de cara a la APP, solo hay una actualizacion del buffer de dibujado, NO de pantalla, //ya que carecemos de acceso directo a la VRAM. //Permitimos HWPALETTEs, cosa que solo se activa si el juego pide un modo de 8bpp porque, //tanto si conseguimos modificar la paleta por hard como si tenemos que indexar los valores //como estamos haciendo hasta ahora emulando asi la paleta, nos interesa que los juegos //entren en SetColors(), y sin paleta por hardware no entran. current->flags |= SDL_FULLSCREEN; if (flags & SDL_DOUBLEBUF){ current->flags &= ~SDL_DOUBLEBUF; } if (flags & SDL_HWSURFACE){ current->flags &= ~SDL_HWSURFACE; current->flags |= SDL_SWSURFACE; } if (flags & SDL_HWPALETTE) current->flags |= SDL_HWPALETTE; current->w = width; current->h = height; current->pitch = dispvars->pitch; current->pixels = dispvars->pixmem; //DISPMANX_FreeHWSurfaces(this); //DISPMANX_InitHWSurfaces(this, current, surfaces_mem, surfaces_len); //this->screen = current; //this->screen = NULL; //Aniadimos el element. dispvars->update = vc_dispmanx_update_start( 0 ); dispvars->element = vc_dispmanx_element_add( dispvars->update, dispvars->display, 0 /*layer*/, &(dispvars->dst_rect), dispvars->resources[flip_page], &(dispvars->src_rect), DISPMANX_PROTECTION_NONE, dispvars->alpha, 0 /*clamp*/, /*VC_IMAGE_ROT0*/ 0 ); vc_dispmanx_update_submit_sync( dispvars->update ); /* We're done */ //MAC Disable graphics 1 //Aqui ponemos la terminal en modo grafico. Ya no se imprimiran mas mensajes en la consola a partir de aqui. go_video_console: if ( DISPMANX_EnterGraphicsMode(this) < 0 ) return(NULL); return(current); }
static bool gfx_ctx_init(void) { RARCH_LOG("[VC/EGL]: Initializing...\n"); if (g_inited) { RARCH_ERR("[VC/EGL]: Attempted to re-initialize driver.\n"); return false; } EGLint num_config; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; DISPMANX_MODEINFO_T dispman_modeinfo; VC_RECT_T dst_rect; VC_RECT_T src_rect; static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; bcm_host_init(); // get an EGL display connection g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!g_egl_dpy) goto error; // initialize the EGL display connection if (!eglInitialize(g_egl_dpy, NULL, NULL)) goto error; // get an appropriate EGL frame buffer configuration if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_config, 1, &num_config)) goto error; // create an EGL rendering context g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, (g_api == GFX_CTX_OPENGL_ES_API) ? context_attributes : NULL); if (!g_egl_ctx) goto error; // create an EGL window surface if (graphics_get_display_size(0 /* LCD */, &g_fb_width, &g_fb_height) < 0) goto error; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = g_fb_width; dst_rect.height = g_fb_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = g_fb_width << 16; src_rect.height = g_fb_height << 16; dispman_display = vc_dispmanx_display_open(0 /* LCD */); vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); dispman_update = vc_dispmanx_update_start(0); VC_DISPMANX_ALPHA_T alpha; alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; alpha.opacity = 255; alpha.mask = 0; dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp*/, DISPMANX_NO_ROTATE); nativewindow.element = dispman_element; nativewindow.width = g_fb_width; nativewindow.height = g_fb_height; vc_dispmanx_update_submit_sync(dispman_update); g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, &nativewindow, NULL); if (!g_egl_surf) goto error; // connect the context to the surface if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) goto error; return true; error: gfx_ctx_destroy(); return false; }
static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data) { int32_t success; EGLBoolean result; EGLint num_config; rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t)); *input = NULL; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; DISPMANX_MODEINFO_T dispman_modeinfo; VC_RECT_T dst_rect; VC_RECT_T src_rect; static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EGLConfig config; bcm_host_init(); // get an EGL display connection rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); rarch_assert(rpi->mDisplay != EGL_NO_DISPLAY); // initialize the EGL display connection result = eglInitialize(rpi->mDisplay, NULL, NULL); rarch_assert(result != EGL_FALSE); eglBindAPI(EGL_OPENVG_API); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config); rarch_assert(result != EGL_FALSE); // create an EGL rendering context rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL); rarch_assert(rpi->mContext != EGL_NO_CONTEXT); // create an EGL window surface success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight); rarch_assert(success >= 0); dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = rpi->mScreenWidth; dst_rect.height = rpi->mScreenHeight; src_rect.x = 0; src_rect.y = 0; src_rect.width = rpi->mScreenWidth << 16; src_rect.height = rpi->mScreenHeight << 16; dispman_display = vc_dispmanx_display_open(0 /* LCD */); vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); 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*/, DISPMANX_NO_ROTATE); nativewindow.element = dispman_element; nativewindow.width = rpi->mScreenWidth; nativewindow.height = rpi->mScreenHeight; vc_dispmanx_update_submit_sync(dispman_update); rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL); rarch_assert(rpi->mSurface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext); rarch_assert(result != EGL_FALSE); rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555; rpi->mKeepAspect = video->force_aspect; // check for SD televisions: they should always be 4:3 if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576)) rpi->mScreenAspect = 4.0f / 3.0f; else rpi->mScreenAspect = (float)dispman_modeinfo.width / dispman_modeinfo.height; VGfloat clearColor[4] = {0, 0, 0, 1}; vgSetfv(VG_CLEAR_COLOR, 4, clearColor); rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; // We can't use the native format because there's no sXRGB_1555 type and // emulation cores can send 0 in the top bit. We lose some speed on // conversion but I doubt it has any real affect, since we are only drawing // one image at the end of the day. Still keep the alpha channel for ABGR. rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, !video->vsync); linuxraw_input_t *linuxraw_input = (linuxraw_input_t*)input_linuxraw.init(); if (linuxraw_input) { *input = (const input_driver_t *)&input_linuxraw; *input_data = linuxraw_input; } #ifdef HAVE_FREETYPE if (g_settings.video.font_enable) { rpi->mFont = vgCreateFont(0); rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); const char *path = g_settings.video.font_path; if (!*path || !path_file_exists(path)) path = font_renderer_get_default_font(); rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight); if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer) { rpi->mFontsOn = true; rpi->mPaintFg = vgCreatePaint(); rpi->mPaintBg = vgCreatePaint(); VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); } } #endif struct sigaction sa; sa.sa_handler = rpi_kill; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); return rpi; }
static void *gfx_ctx_vc_init(video_frame_info_t *video_info, void *video_driver) { VC_DISPMANX_ALPHA_T alpha; EGLint n, major, minor; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; DISPMANX_MODEINFO_T dispman_modeinfo; VC_RECT_T dst_rect; VC_RECT_T src_rect; #ifdef HAVE_EGL static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; #endif settings_t *settings = config_get_ptr(); vc_ctx_data_t *vc = NULL; if (g_egl_inited) { RARCH_ERR("[VC/EGL]: Attempted to re-initialize driver.\n"); return NULL; } vc = (vc_ctx_data_t*)calloc(1, sizeof(*vc)); if (!vc) return NULL; /* If we set this env variable, Broadcom's EGL implementation will block * on vsync with a double buffer when we call eglSwapBuffers. Less input lag! * Has to be done before any EGL call. * NOTE this is commented out because it should be the right way to do it, but * currently it doesn't work, so we are using an vsync callback based solution.*/ /* if (video_info->max_swapchain_images <= 2) setenv("V3D_DOUBLE_BUFFER", "1", 1); else setenv("V3D_DOUBLE_BUFFER", "0", 1); */ bcm_host_init(); #ifdef HAVE_EGL if (!egl_init_context(&vc->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribute_list)) { egl_report_error(); goto error; } if (!egl_create_context(&vc->egl, (vc_api == GFX_CTX_OPENGL_ES_API) ? context_attributes : NULL)) { egl_report_error(); goto error; } #endif /* Create an EGL window surface. */ if (graphics_get_display_size(0 /* LCD */, &vc->fb_width, &vc->fb_height) < 0) goto error; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = vc->fb_width; dst_rect.height = vc->fb_height; src_rect.x = 0; src_rect.y = 0; /* Use dispmanx upscaling if fullscreen_x * and fullscreen_y are set. */ if ((settings->uints.video_fullscreen_x != 0) && (settings->uints.video_fullscreen_y != 0)) { /* Keep input and output aspect ratio equal. * There are other aspect ratio settings which can be used to stretch video output. */ /* Calculate source and destination aspect ratios. */ float srcAspect = (float)settings->uints.video_fullscreen_x / (float)settings->uints.video_fullscreen_y; float dstAspect = (float)vc->fb_width / (float)vc->fb_height; /* If source and destination aspect ratios are not equal correct source width. */ if (srcAspect != dstAspect) src_rect.width = (unsigned)(settings->uints.video_fullscreen_y * dstAspect) << 16; else src_rect.width = settings->uints.video_fullscreen_x << 16; src_rect.height = settings->uints.video_fullscreen_y << 16; } else { src_rect.width = vc->fb_width << 16; src_rect.height = vc->fb_height << 16; } dispman_display = vc_dispmanx_display_open(0 /* LCD */); vc->dispman_display = dispman_display; vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); dispman_update = vc_dispmanx_update_start(0); alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; alpha.opacity = 255; alpha.mask = 0; dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp*/, DISPMANX_NO_ROTATE); vc->native_window.element = dispman_element; /* Use dispmanx upscaling if fullscreen_x and fullscreen_y are set. */ if (settings->uints.video_fullscreen_x != 0 && settings->uints.video_fullscreen_y != 0) { /* Keep input and output aspect ratio equal. * There are other aspect ratio settings which * can be used to stretch video output. */ /* Calculate source and destination aspect ratios. */ float srcAspect = (float)settings->uints.video_fullscreen_x / (float)settings->uints.video_fullscreen_y; float dstAspect = (float)vc->fb_width / (float)vc->fb_height; /* If source and destination aspect ratios are not equal correct source width. */ if (srcAspect != dstAspect) vc->native_window.width = (unsigned)(settings->uints.video_fullscreen_y * dstAspect); else vc->native_window.width = settings->uints.video_fullscreen_x; vc->native_window.height = settings->uints.video_fullscreen_y; } else { vc->native_window.width = vc->fb_width; vc->native_window.height = vc->fb_height; } vc_dispmanx_update_submit_sync(dispman_update); #ifdef HAVE_EGL if (!egl_create_surface(&vc->egl, &vc->native_window)) goto error; #endif /* For vsync after eglSwapBuffers when max_swapchain < 3 */ vc->vsync_condition = scond_new(); vc->vsync_condition_mutex = slock_new(); vc->vsync_callback_set = false; if (video_info->max_swapchain_images <= 2) { /* Start sending vsync callbacks so we can wait for vsync after eglSwapBuffers */ vc_dispmanx_vsync_callback(vc->dispman_display, dispmanx_vsync_callback, (void*)vc); vc->vsync_callback_set = true; } return vc; error: gfx_ctx_vc_destroy(video_driver); return NULL; }
static void open_screen(struct uae_prefs *p) { VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T ) (DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 255, /*alpha 0->255*/ 0 }; uint32_t vc_image_ptr; int width; int height; #ifdef PICASSO96 if (screen_is_picasso) { width = picasso_vidinfo.width; height = picasso_vidinfo.height; } else #endif { p->gfx_resolution = p->gfx_size.width > 600 ? 1 : 0; width = p->gfx_size.width; height = p->gfx_size.height; } //if(prSDLScreen != NULL) //{ // SDL_FreeSurface(prSDLScreen); // prSDLScreen = NULL; //} if(Dummy_prSDLScreen == NULL ) { const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo (); printf("DispmanX: Current resolution: %d x %d %d bpp\n",videoInfo->current_w, videoInfo->current_h, videoInfo->vfmt->BitsPerPixel); Dummy_prSDLScreen = SDL_SetVideoMode(videoInfo->current_w,videoInfo->current_h,16,SDL_SWSURFACE |SDL_FULLSCREEN); //Dummy_prSDLScreen = SDL_SetVideoMode(800,480,16,SDL_SWSURFACE ); } SDL_ShowCursor(SDL_DISABLE); // check if resolution hasn't change in menu. otherwise free the resources so that they will be re-generated with new resolution. if ((dispmanxresource_amigafb_1 != 0) && ((blit_rect.width != width) || (blit_rect.height != height) || (currprefs.gfx_correct_aspect != changed_prefs.gfx_correct_aspect))) { printf("Emulation resolution change detected.\n"); if(prSDLScreen != NULL ) { SDL_FreeSurface(prSDLScreen); prSDLScreen = 0; } graphics_dispmanshutdown(); vc_dispmanx_resource_delete( dispmanxresource_amigafb_1 ); vc_dispmanx_resource_delete( dispmanxresource_amigafb_2 ); dispmanxresource_amigafb_1 = 0; dispmanxresource_amigafb_2 = 0; } if (dispmanxresource_amigafb_1 == 0) { printf("Emulation resolution: Width %i Height: %i\n",width,height); currprefs.gfx_correct_aspect = changed_prefs.gfx_correct_aspect; prSDLScreen = SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,16, Dummy_prSDLScreen->format->Rmask, Dummy_prSDLScreen->format->Gmask, Dummy_prSDLScreen->format->Bmask, Dummy_prSDLScreen->format->Amask); dispmanxdisplay = vc_dispmanx_display_open( 0 ); vc_dispmanx_display_get_info( dispmanxdisplay, &dispmanxdinfo); dispmanxresource_amigafb_1 = vc_dispmanx_resource_create( VC_IMAGE_RGB565, width, height, &vc_image_ptr); dispmanxresource_amigafb_2 = vc_dispmanx_resource_create( VC_IMAGE_RGB565, width, height, &vc_image_ptr); vc_dispmanx_rect_set( &blit_rect, 0, 0, width,height); vc_dispmanx_resource_write_data( dispmanxresource_amigafb_1, VC_IMAGE_RGB565, width *2, prSDLScreen->pixels, &blit_rect ); vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 ); } // 16/9 to 4/3 ratio adaptation. if (currprefs.gfx_correct_aspect == 0) { // Fullscreen. vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width * 1)/100, (dispmanxdinfo.height * 2)/100 , dispmanxdinfo.width - (dispmanxdinfo.width * 2)/100 , dispmanxdinfo.height - (dispmanxdinfo.height * 4)/100 ); } else { // 4/3 shrink. vc_dispmanx_rect_set( &dst_rect, ((dispmanxdinfo.width * 13)/100) , (dispmanxdinfo.height * 2)/100 , (dispmanxdinfo.width - ((dispmanxdinfo.width * 26)/100)) , dispmanxdinfo.height - (dispmanxdinfo.height * 4)/100 ); } // For debug, in order to avoid full screen. //vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width /2), // (dispmanxdinfo.height /2) , // (dispmanxdinfo.width - (dispmanxdinfo.width * 6)/100 )/2, // (dispmanxdinfo.height - (dispmanxdinfo.height * 7)/100 )/2); if (DispManXElementpresent == 0) { DispManXElementpresent = 1; dispmanxupdate = vc_dispmanx_update_start( 10 ); dispmanxelement = vc_dispmanx_element_add( dispmanxupdate, dispmanxdisplay, 2000, // layer &dst_rect, dispmanxresource_amigafb_1, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, // clamp DISPMANX_NO_ROTATE ); vc_dispmanx_update_submit(dispmanxupdate,NULL,NULL); //dispmanxupdate = vc_dispmanx_update_start( 10 ); } if(prSDLScreen != NULL) { InitAmigaVidMode(p); init_row_map(); } //framecnt = 1; // Don't draw frame before reset done }
int main( int argc, char *argv[]) { int opt = 0; bool writeToStdout = false; char *pngName = DEFAULT_NAME; int32_t requestedWidth = 0; int32_t requestedHeight = 0; uint32_t displayNumber = DEFAULT_DISPLAY_NUMBER; int compression = Z_DEFAULT_COMPRESSION; int delay = DEFAULT_DELAY; VC_IMAGE_TYPE_T imageType = VC_IMAGE_RGBA32; int8_t dmxBytesPerPixel = 4; int result = 0; program = basename(argv[0]); //------------------------------------------------------------------- char *sopts = "c:d:D:Hh:p:w:s"; struct option lopts[] = { { "compression", required_argument, NULL, 'c' }, { "delay", required_argument, NULL, 'd' }, { "display", required_argument, NULL, 'D' }, { "height", required_argument, NULL, 'h' }, { "help", no_argument, NULL, 'H' }, { "pngname", required_argument, NULL, 'p' }, { "width", required_argument, NULL, 'w' }, { "stdout", no_argument, NULL, 's' }, { NULL, no_argument, NULL, 0 } }; while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { switch (opt) { case 'c': compression = atoi(optarg); if ((compression < 0) || (compression > 9)) { compression = Z_DEFAULT_COMPRESSION; } break; case 'd': delay = atoi(optarg); break; case 'D': displayNumber = atoi(optarg); break; case 'h': requestedHeight = atoi(optarg); break; case 'p': pngName = optarg; break; case 'w': requestedWidth = atoi(optarg); break; case 's': writeToStdout = true; break; case 'H': default: usage(); if (opt == 'H') { exit(EXIT_SUCCESS); } else { exit(EXIT_FAILURE); } break; } } //------------------------------------------------------------------- bcm_host_init(); //------------------------------------------------------------------- // // When the display is rotate (either 90 or 270 degrees) we need to // swap the width and height of the snapshot // char response[1024]; int displayRotated = 0; if (vc_gencmd(response, sizeof(response), "get_config int") == 0) { vc_gencmd_number_property(response, "display_rotate", &displayRotated); } //------------------------------------------------------------------- if (delay) { sleep(delay); } //------------------------------------------------------------------- DISPMANX_DISPLAY_HANDLE_T displayHandle = vc_dispmanx_display_open(displayNumber); if (displayHandle == 0) { fprintf(stderr, "%s: unable to open display %d\n", program, displayNumber); exit(EXIT_FAILURE); } DISPMANX_MODEINFO_T modeInfo; result = vc_dispmanx_display_get_info(displayHandle, &modeInfo); if (result != 0) { fprintf(stderr, "%s: unable to get display information\n", program); exit(EXIT_FAILURE); } int32_t pngWidth = modeInfo.width; int32_t pngHeight = modeInfo.height; if (requestedWidth > 0) { pngWidth = requestedWidth; if (requestedHeight == 0) { double numerator = modeInfo.height * requestedWidth; double denominator = modeInfo.width; pngHeight = (int32_t)ceil(numerator / denominator); } } if (requestedHeight > 0) { pngHeight = requestedHeight; if (requestedWidth == 0) { double numerator = modeInfo.width * requestedHeight; double denominator = modeInfo.height; pngWidth = (int32_t)ceil(numerator / denominator); } } //------------------------------------------------------------------- // only need to check low bit of displayRotated (value of 1 or 3). // If the display is rotated either 90 or 270 degrees (value 1 or 3) // the width and height need to be transposed. int32_t dmxWidth = pngWidth; int32_t dmxHeight = pngHeight; if (displayRotated & 1) { dmxWidth = pngHeight; dmxHeight = pngWidth; } int32_t dmxPitch = dmxBytesPerPixel * ALIGN_TO_16(dmxWidth); void *dmxImagePtr = malloc(dmxPitch * dmxHeight); if (dmxImagePtr == NULL) { fprintf(stderr, "%s: unable to allocated image buffer\n", program); exit(EXIT_FAILURE); } //------------------------------------------------------------------- uint32_t vcImagePtr = 0; DISPMANX_RESOURCE_HANDLE_T resourceHandle; resourceHandle = vc_dispmanx_resource_create(imageType, dmxWidth, dmxHeight, &vcImagePtr); result = vc_dispmanx_snapshot(displayHandle, resourceHandle, DISPMANX_NO_ROTATE); if (result != 0) { vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); fprintf(stderr, "%s: vc_dispmanx_snapshot() failed\n", program); exit(EXIT_FAILURE); } VC_RECT_T rect; result = vc_dispmanx_rect_set(&rect, 0, 0, dmxWidth, dmxHeight); if (result != 0) { vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); fprintf(stderr, "%s: vc_dispmanx_rect_set() failed\n", program); exit(EXIT_FAILURE); } result = vc_dispmanx_resource_read_data(resourceHandle, &rect, dmxImagePtr, dmxPitch); if (result != 0) { vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); fprintf(stderr, "%s: vc_dispmanx_resource_read_data() failed\n", program); exit(EXIT_FAILURE); } vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); //------------------------------------------------------------------- // Convert from RGBA (32 bit) to RGB (24 bit) int8_t pngBytesPerPixel = 3; int32_t pngPitch = pngBytesPerPixel * pngWidth; void *pngImagePtr = malloc(pngPitch * pngHeight); int32_t j = 0; for (j = 0 ; j < pngHeight ; j++) { int32_t dmxXoffset = 0; int32_t dmxYoffset = 0; switch (displayRotated & 3) { case 0: // 0 degrees if (displayRotated & 0x20000) // flip vertical { dmxYoffset = (dmxHeight - j - 1) * dmxPitch; } else { dmxYoffset = j * dmxPitch; } break; case 1: // 90 degrees if (displayRotated & 0x20000) // flip vertical { dmxXoffset = j * dmxBytesPerPixel; } else { dmxXoffset = (dmxWidth - j - 1) * dmxBytesPerPixel; } break; case 2: // 180 degrees if (displayRotated & 0x20000) // flip vertical { dmxYoffset = j * dmxPitch; } else { dmxYoffset = (dmxHeight - j - 1) * dmxPitch; } break; case 3: // 270 degrees if (displayRotated & 0x20000) // flip vertical { dmxXoffset = (dmxWidth - j - 1) * dmxBytesPerPixel; } else { dmxXoffset = j * dmxBytesPerPixel; } break; } int32_t i = 0; for (i = 0 ; i < pngWidth ; i++) { uint8_t *pngPixelPtr = pngImagePtr + (i * pngBytesPerPixel) + (j * pngPitch); switch (displayRotated & 3) { case 0: // 0 degrees if (displayRotated & 0x10000) // flip horizontal { dmxXoffset = (dmxWidth - i - 1) * dmxBytesPerPixel; } else { dmxXoffset = i * dmxBytesPerPixel; } break; case 1: // 90 degrees if (displayRotated & 0x10000) // flip horizontal { dmxYoffset = (dmxHeight - i - 1) * dmxPitch; } else { dmxYoffset = i * dmxPitch; } break; case 2: // 180 degrees if (displayRotated & 0x10000) // flip horizontal { dmxXoffset = i * dmxBytesPerPixel; } else { dmxXoffset = (dmxWidth - i - 1) * dmxBytesPerPixel; } break; case 3: // 270 degrees if (displayRotated & 0x10000) // flip horizontal { dmxYoffset = i * dmxPitch; } else { dmxYoffset = (dmxHeight - i - 1) * dmxPitch; } break; } uint8_t *dmxPixelPtr = dmxImagePtr + dmxXoffset + dmxYoffset; memcpy(pngPixelPtr, dmxPixelPtr, 3); } } free(dmxImagePtr); dmxImagePtr = NULL; //------------------------------------------------------------------- png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (pngPtr == NULL) { fprintf(stderr, "%s: unable to allocated PNG write structure\n", program); exit(EXIT_FAILURE); } png_infop infoPtr = png_create_info_struct(pngPtr); if (infoPtr == NULL) { fprintf(stderr, "%s: unable to allocated PNG info structure\n", program); exit(EXIT_FAILURE); } if (setjmp(png_jmpbuf(pngPtr))) { fprintf(stderr, "%s: unable to create PNG\n", program); exit(EXIT_FAILURE); } FILE *pngfp = NULL; if (writeToStdout) { pngfp = stdout; } else { pngfp = fopen(pngName, "wb"); if (pngfp == NULL) { fprintf(stderr, "%s: unable to create %s - %s\n", program, pngName, strerror(errno)); exit(EXIT_FAILURE); } } png_init_io(pngPtr, pngfp); png_set_IHDR( pngPtr, infoPtr, pngWidth, pngHeight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (compression != Z_DEFAULT_COMPRESSION) { png_set_compression_level(pngPtr, compression); } png_write_info(pngPtr, infoPtr); int y = 0; for (y = 0; y < pngHeight; y++) { png_write_row(pngPtr, pngImagePtr + (pngPitch * y)); } png_write_end(pngPtr, NULL); png_destroy_write_struct(&pngPtr, &infoPtr); if (pngfp != stdout) { fclose(pngfp); } //------------------------------------------------------------------- free(pngImagePtr); pngImagePtr = NULL; return 0; }
static int DISPMANX_VideoInit(_THIS, SDL_PixelFormat *vformat) { int i; int ret = 0; #if !SDL_THREADS_DISABLED /* Create the hardware surface lock mutex */ hw_lock = SDL_CreateMutex(); if ( hw_lock == NULL ) { SDL_SetError("Unable to create lock mutex"); DISPMANX_VideoQuit(this); return(-1); } #endif //MAC Inicializamos el SOC bcm_host_init(); //MAC Abrimos el display dispmanx uint32_t screen = 0; printf("dispmanx: Opening display[%i]...\n", screen ); dispvars->display = vc_dispmanx_display_open( screen ); //MAC Recuperamos algunos datos de la configuración del buffer actual vc_dispmanx_display_get_info( dispvars->display, &(dispvars->amode)); assert(ret == 0); vformat->BitsPerPixel = 16; //Pon lo que quieras.Era para restaurar fb //MAC Para que las funciones GetVideoInfo() devuelvan un SDL_VideoInfo con contenidos. this->info.current_w = dispvars->amode.width; this->info.current_h = dispvars->amode.height; this->info.wm_available = 0; this->info.hw_available = 1; this->info.video_mem = 32768 /1024; printf( "Physical video mode is %d x %d\n", dispvars->amode.width, dispvars->amode.height ); /* Limpiamos LAS listas de modos disponibles */ for ( i=0; i<NUM_MODELISTS; ++i ) { SDL_nummodes[i] = 0; SDL_modelist[i] = NULL; } // Añadimos nuestros modos de vídeo //En DISPMANX sólo tenemos el modo de vídeo que se está usando //actualmente, sea cual sea, y los demás modos se escalan a ese //por hardware. SDL NO entiende de timings (incluyendo tasas de //refresco), así que eso no se tiene que resolver aquí, supongo. for (i = 0; i < NUM_MODELISTS; i++){ //Añado cada modo a la lista 0 (8bpp), lista 1 (16), lista 2(24).. //Por eso itero hasta NUM_MODELIST: cada MODELIST es para un bpp. DISPMANX_AddMode(this, i, dispvars->amode.width, dispvars->amode.height, 0); printf("Adding video mode: %d x %d - %d bpp\n", dispvars->amode.width, dispvars->amode.height, (i+1)*8); } /* Enable mouse and keyboard support */ if ( DISPMANX_OpenKeyboard(this) < 0 ) { DISPMANX_VideoQuit(this); return(-1); } if ( DISPMANX_OpenMouse(this) < 0 ) { const char *sdl_nomouse; //MAC Si esto da problemas, es por los premisos de gpm sobre //el ratón en /dev/mice. Edita /etc/init.d/gpm y añade //en la sección start() la línea chmod 0666{MOUSEDEV} sdl_nomouse = SDL_getenv("SDL_NOMOUSE"); if ( ! sdl_nomouse ) { printf("\nERR - Couldn't open mouse. Look for permissions in /etc/init.d/gpm.\n"); DISPMANX_VideoQuit(this); return(-1); } } /* We're done! */ return(0); }
int main(int argc, char** argv) { cam = new PiCam(160, 120, &process_frame); std::cout << "Initialized camera" << std::endl; int ret; display = vc_dispmanx_display_open(0); // "window" std::cout << "Opened display" << std::endl; unsigned int vc_image_ptr; display_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB888, 160 | (160*3) << 16, 120, &vc_image_ptr); std::cout << "Created resource" << std::endl; VC_DISPMANX_ALPHA_T alpha = { /*DISPMANX_FLAGS_ALPHA_FROM_SOURCE |*/ DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, /*alpha 0->255*/ 0 }; VC_RECT_T dst_rect; VC_RECT_T src_rect; DISPMANX_MODEINFO_T info; ret = vc_dispmanx_display_get_info(display, &info); assert(ret==0); std::cout << "Got display info" << std::endl; //vc_dispmanx_rect_set( &dst_rect, 0, 0, 160, 120); vc_dispmanx_rect_set( &src_rect, 0, 0, 160<<16, 120<<16); vc_dispmanx_rect_set( &dst_rect, ( info.width - 160 ) / 2, ( info.height - 120 ) / 2, 160, 120 ); DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(10); assert(update != DISPMANX_NO_HANDLE); std::cout << "Started update" << std::endl; element = vc_dispmanx_element_add( update, display, 2000, // layer &dst_rect, display_resource, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, // clamp //VC_IMAGE_ROT0 ); DISPMANX_NO_ROTATE); std::cout << "Added element" << std::endl; ret = vc_dispmanx_update_submit_sync(update); assert(ret == 0); std::cout << "Finished update" << std::endl; //cv::namedWindow("RPi Cam Raw", cv::WINDOW_AUTOSIZE); //cv::namedWindow("RPi Cam Proc", cv::WINDOW_AUTOSIZE); //hist = cv::Mat(240, 320, CV_8UC3, 0); /* cv::createTrackbar("Hue", "RPi Cam", &hue, 255, &doNothing); cv::createTrackbar("Range", "RPi Cam", &range, 128, &doNothing); cv::createTrackbar("Min Sat", "RPi Cam", &s_min, 255, &doNothing); cv::createTrackbar("Max Sat", "RPi Cam", &s_max, 255, &doNothing); cv::createTrackbar("Min Value", "RPi Cam", &v_min, 255, &doNothing); cv::createTrackbar("Max Value", "RPi Cam", &v_max, 255, &doNothing); */ //cv::createTrackbar("Histogram", "RPi Cam Raw", &_hist_, 1, &doHistogram); //cv::createTrackbar("Threshold", "RPi Cam Raw", &threshold, 1000, &doNothing); std::cout << "Setup dispmanx" << std::endl; cam->start(); //vcos_sleep(100000); //std::cout << (n / 100.0) << " FPS\n"; //cv::waitKey(0); return 0; }
static bool dispmanx_setup_scale(void *data, unsigned width, unsigned height, unsigned pitch) { int i, dst_ypos; VC_DISPMANX_ALPHA_T layerAlpha; struct dispmanx_video *_dispvars = data; if (!_dispvars) return false; /* Since internal frame resolution seems to have changed, we change the * internal frame resolution in use, and call dispmanx_setup_scale() * again to set the rects, etc. */ _dispvars->width = width; _dispvars->height = height; /* Total pitch, including things the cores * render between "visible" scanlines. */ _dispvars->pitch = pitch; /* The "visible" width obtained from the core pitch. */ _dispvars->visible_width = pitch / _dispvars->bytes_per_pixel; dispmanx_free_main_resources(_dispvars); vc_dispmanx_display_get_info(_dispvars->display, &(_dispvars->amode)); // We choose the pixel format depending on the bpp of the frame. switch (_dispvars->bytes_per_pixel) { case 2: _dispvars->pixFormat = VC_IMAGE_RGB565; break; case 4: _dispvars->pixFormat = VC_IMAGE_XRGB8888; break; default: RARCH_ERR("video_dispmanx: wrong pixel format\n"); return NULL; } /* Transparency disabled */ layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; layerAlpha.opacity = 255; layerAlpha.mask = 0; _dispvars->alpha = &layerAlpha; switch (g_settings.video.aspect_ratio_idx) { case ASPECT_RATIO_4_3: _dispvars->aspect = (float)4 / (float)3; break; case ASPECT_RATIO_16_9: _dispvars->aspect = (float)16 / (float)9; break; case ASPECT_RATIO_16_10: _dispvars->aspect = (float)16 / (float)10; break; case ASPECT_RATIO_16_15: _dispvars->aspect = (float)16 / (float)15; break; case ASPECT_RATIO_CORE: _dispvars->aspect = (float)_dispvars->width / (float)_dispvars->height; break; default: _dispvars->aspect = (float)_dispvars->width / (float)_dispvars->height; break; } int dst_width = _dispvars->amode.height * _dispvars->aspect; /* If we obtain a scaled image width that is bigger than the physical screen width, * then we keep the physical screen width as our maximun width. */ #if 0 if (dst_width > _dispvars->amode.width) dst_width = _dispvars->amode.width; #endif dst_ypos = (_dispvars->amode.width - dst_width) / 2; vc_dispmanx_rect_set(&(_dispvars->dstRect), dst_ypos, 0, dst_width, _dispvars->amode.height); /* We configure the rects now. */ vc_dispmanx_rect_set(&(_dispvars->bmpRect), 0, 0, _dispvars->width, _dispvars->height); vc_dispmanx_rect_set(&(_dispvars->srcRect), 0, 0, _dispvars->width << 16, _dispvars->height << 16); /* We create as many resources as pages */ for (i = 0; i < NUMPAGES; i++) _dispvars->resources[i] = vc_dispmanx_resource_create(_dispvars->pixFormat, _dispvars->visible_width, _dispvars->height, &(_dispvars->vcImagePtr)); /* Add element. */ _dispvars->update = vc_dispmanx_update_start(0); _dispvars->element = vc_dispmanx_element_add(_dispvars->update, _dispvars->display, 0, &(_dispvars->dstRect), _dispvars->resources[0], &(_dispvars->srcRect), DISPMANX_PROTECTION_NONE, _dispvars->alpha, 0, (DISPMANX_TRANSFORM_T)0); vc_dispmanx_update_submit_sync(_dispvars->update); return true; }
static void *gfx_ctx_vc_init(void *video_driver) { VC_DISPMANX_ALPHA_T alpha; EGLint n, major, minor; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; DISPMANX_MODEINFO_T dispman_modeinfo; VC_RECT_T dst_rect; VC_RECT_T src_rect; #ifdef HAVE_EGL static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; #endif settings_t *settings = config_get_ptr(); vc_ctx_data_t *vc = NULL; if (g_egl_inited) { RARCH_ERR("[VC/EGL]: Attempted to re-initialize driver.\n"); return NULL; } vc = (vc_ctx_data_t*)calloc(1, sizeof(*vc)); if (!vc) return NULL; bcm_host_init(); #ifdef HAVE_EGL if (!egl_init_context(&vc->egl, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribute_list)) { egl_report_error(); goto error; } if (!egl_create_context(&vc->egl, (vc_api == GFX_CTX_OPENGL_ES_API) ? context_attributes : NULL)) { egl_report_error(); goto error; } #endif /* Create an EGL window surface. */ if (graphics_get_display_size(0 /* LCD */, &vc->fb_width, &vc->fb_height) < 0) goto error; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = vc->fb_width; dst_rect.height = vc->fb_height; src_rect.x = 0; src_rect.y = 0; /* Use dispmanx upscaling if fullscreen_x * and fullscreen_y are set. */ if (settings->video.fullscreen_x != 0 && settings->video.fullscreen_y != 0) { /* Keep input and output aspect ratio equal. * There are other aspect ratio settings which can be used to stretch video output. */ /* Calculate source and destination aspect ratios. */ float srcAspect = (float)settings->video.fullscreen_x / (float)settings->video.fullscreen_y; float dstAspect = (float)vc->fb_width / (float)vc->fb_height; /* If source and destination aspect ratios are not equal correct source width. */ if (srcAspect != dstAspect) src_rect.width = (unsigned)(settings->video.fullscreen_y * dstAspect) << 16; else src_rect.width = settings->video.fullscreen_x << 16; src_rect.height = settings->video.fullscreen_y << 16; } else { src_rect.width = vc->fb_width << 16; src_rect.height = vc->fb_height << 16; } dispman_display = vc_dispmanx_display_open(0 /* LCD */); vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); dispman_update = vc_dispmanx_update_start(0); alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; alpha.opacity = 255; alpha.mask = 0; dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp*/, DISPMANX_NO_ROTATE); nativewindow.element = dispman_element; /* Use dispmanx upscaling if fullscreen_x and fullscreen_y are set. */ if (settings->video.fullscreen_x != 0 && settings->video.fullscreen_y != 0) { /* Keep input and output aspect ratio equal. * There are other aspect ratio settings which * can be used to stretch video output. */ /* Calculate source and destination aspect ratios. */ float srcAspect = (float)settings->video.fullscreen_x / (float)settings->video.fullscreen_y; float dstAspect = (float)vc->fb_width / (float)vc->fb_height; /* If source and destination aspect ratios are not equal correct source width. */ if (srcAspect != dstAspect) nativewindow.width = (unsigned)(settings->video.fullscreen_y * dstAspect); else nativewindow.width = settings->video.fullscreen_x; nativewindow.height = settings->video.fullscreen_y; } else { nativewindow.width = vc->fb_width; nativewindow.height = vc->fb_height; } vc_dispmanx_update_submit_sync(dispman_update); #ifdef HAVE_EGL if (!egl_create_surface(&vc->egl, &nativewindow)) goto error; #endif return vc; error: gfx_ctx_vc_destroy(video_driver); return NULL; }
static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win) { int wid = (int)win; if(wid>-NUM_WIN && wid <=0) { /* * Special identifiers indicating the default windows. Either use the * one we've got or create a new one * simple hack for VMCSX_VC4_1.0 release to demonstrate concurrent running of apps under linux * win == 0 => full screen window on display 0 * win == -1 => 1/4 screen top left window on display 0 * win == -2 => 1/4 screen top right window on display 0 * win == -3 => 1/4 screen bottom left window on display 0 * win == -4 => 1/4 screen bottom right window on display 0 * win == -5 => full screen window on display 2 * it is expected that Open WFC will provide a proper mechanism in the near future */ wid = -wid; if (!have_default_dwin[wid]) { DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( (wid == 5) ? 2 : 0 ); DISPMANX_MODEINFO_T info; vc_dispmanx_display_get_info(display, &info); int32_t dw = info.width, dh = info.height; DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start( 0 ); VC_DISPMANX_ALPHA_T alpha = {DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0}; VC_RECT_T dst_rect; VC_RECT_T src_rect; int x, y, width, height, layer; switch(wid) { case 0: x = 0; y = 0; width = dw; height = dh; layer = 0; break; case 1: x = 0; y = 0; width = dw/2; height = dh/2; layer = 0; break; case 2: x = dw/2; y = 0; width = dw/2; height = dh/2; layer = 0; break; case 3: x = 0; y = dh/2; width = dw/2; height = dh/2; layer = 0; break; case 4: x = dw/2; y = dh/2; width = dw/2; height = dh/2; layer = 0; break; case 5: x = 0; y = 0; width = dw; height = dh; layer = 0; break; } src_rect.x = 0; src_rect.y = 0; src_rect.width = width << 16; src_rect.height = height << 16; dst_rect.x = x; dst_rect.y = y; dst_rect.width = width; dst_rect.height = height; default_dwin[wid].element = vc_dispmanx_element_add ( update, display, layer, &dst_rect, 0/*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0/*clamp*/, 0/*transform*/); default_dwin[wid].width = width; default_dwin[wid].height = height; vc_dispmanx_update_submit_sync( update ); have_default_dwin[wid] = true; } return &default_dwin[wid]; } else return (EGL_DISPMANX_WINDOW_T*)win; }
static bool gfx_ctx_vc_init(void *data) { EGLint num_config; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; DISPMANX_MODEINFO_T dispman_modeinfo; VC_RECT_T dst_rect; VC_RECT_T src_rect; static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; settings_t *settings = config_get_ptr(); RARCH_LOG("[VC/EGL]: Initializing...\n"); if (g_inited) { RARCH_ERR("[VC/EGL]: Attempted to re-initialize driver.\n"); return false; } bcm_host_init(); /* Get an EGL display connection. */ g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!g_egl_dpy) goto error; /* Initialize the EGL display connection. */ if (!eglInitialize(g_egl_dpy, NULL, NULL)) goto error; /* Get an appropriate EGL frame buffer configuration. */ if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_egl_config, 1, &num_config)) goto error; /* Create an EGL rendering context. */ g_egl_ctx = eglCreateContext( g_egl_dpy, g_egl_config, EGL_NO_CONTEXT, (g_api == GFX_CTX_OPENGL_ES_API) ? context_attributes : NULL); if (!g_egl_ctx) goto error; if (g_use_hw_ctx) { g_egl_hw_ctx = eglCreateContext(g_egl_dpy, g_egl_config, g_egl_ctx, context_attributes); RARCH_LOG("[VC/EGL]: Created shared context: %p.\n", (void*)g_egl_hw_ctx); if (g_egl_hw_ctx == EGL_NO_CONTEXT) goto error; } /* Create an EGL window surface. */ if (graphics_get_display_size(0 /* LCD */, &g_fb_width, &g_fb_height) < 0) goto error; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = g_fb_width; dst_rect.height = g_fb_height; src_rect.x = 0; src_rect.y = 0; /* Use dispmanx upscaling if fullscreen_x * and fullscreen_y are set. */ if (settings->video.fullscreen_x != 0 && settings->video.fullscreen_y != 0) { /* Keep input and output aspect ratio equal. * There are other aspect ratio settings which can be used to stretch video output. */ /* Calculate source and destination aspect ratios. */ float srcAspect = (float)settings->video.fullscreen_x / (float)settings->video.fullscreen_y; float dstAspect = (float)g_fb_width / (float)g_fb_height; /* If source and destination aspect ratios are not equal correct source width. */ if (srcAspect != dstAspect) src_rect.width = (unsigned)(settings->video.fullscreen_y * dstAspect) << 16; else src_rect.width = settings->video.fullscreen_x << 16; src_rect.height = settings->video.fullscreen_y << 16; } else { src_rect.width = g_fb_width << 16; src_rect.height = g_fb_height << 16; } dispman_display = vc_dispmanx_display_open(0 /* LCD */); vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); dispman_update = vc_dispmanx_update_start(0); VC_DISPMANX_ALPHA_T alpha; alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; alpha.opacity = 255; alpha.mask = 0; dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp*/, DISPMANX_NO_ROTATE); nativewindow.element = dispman_element; /* Use dispmanx upscaling if fullscreen_x and fullscreen_y are set. */ if (settings->video.fullscreen_x != 0 && settings->video.fullscreen_y != 0) { /* Keep input and output aspect ratio equal. * There are other aspect ratio settings which * can be used to stretch video output. */ /* Calculate source and destination aspect ratios. */ float srcAspect = (float)settings->video.fullscreen_x / (float)settings->video.fullscreen_y; float dstAspect = (float)g_fb_width / (float)g_fb_height; /* If source and destination aspect ratios are not equal correct source width. */ if (srcAspect != dstAspect) nativewindow.width = (unsigned)(settings->video.fullscreen_y * dstAspect); else nativewindow.width = settings->video.fullscreen_x; nativewindow.height = settings->video.fullscreen_y; } else { nativewindow.width = g_fb_width; nativewindow.height = g_fb_height; } vc_dispmanx_update_submit_sync(dispman_update); g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_egl_config, &nativewindow, NULL); if (!g_egl_surf) goto error; /* Connect the context to the surface. */ if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) goto error; return true; error: gfx_ctx_vc_destroy(data); return false; }
static void *display_thread (void *unused) { VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 255 /*alpha 0->255*/ , 0 }; uint32_t vc_image_ptr; SDL_Surface *Dummy_prSDLScreen; int width, height; bool callback_registered = false; for(;;) { display_thread_busy = false; uae_u32 signal = read_comm_pipe_u32_blocking(display_pipe); display_thread_busy = true; switch(signal) { case DISPLAY_SIGNAL_SETUP: if(!callback_registered) { bcm_host_init(); dispmanxdisplay = vc_dispmanx_display_open(0); vc_dispmanx_vsync_callback(dispmanxdisplay, vsync_callback, NULL); callback_registered = true; } break; case DISPLAY_SIGNAL_SUBSHUTDOWN: if (DispManXElementpresent == 1) { DispManXElementpresent = 0; dispmanxupdate = vc_dispmanx_update_start(0); vc_dispmanx_element_remove(dispmanxupdate, dispmanxelement); vc_dispmanx_update_submit_sync(dispmanxupdate); } if (dispmanxresource_amigafb_1 != 0) { vc_dispmanx_resource_delete(dispmanxresource_amigafb_1); dispmanxresource_amigafb_1 = 0; } if (dispmanxresource_amigafb_2 != 0) { vc_dispmanx_resource_delete(dispmanxresource_amigafb_2); dispmanxresource_amigafb_2 = 0; } if(prSDLScreen != NULL) { SDL_FreeSurface(prSDLScreen); prSDLScreen = NULL; } uae_sem_post (&display_sem); break; case DISPLAY_SIGNAL_OPEN: width = display_width; height = display_height; Dummy_prSDLScreen = SDL_SetVideoMode(width, height, 16, SDL_SWSURFACE | SDL_FULLSCREEN); prSDLScreen = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height, 16, Dummy_prSDLScreen->format->Rmask, Dummy_prSDLScreen->format->Gmask, Dummy_prSDLScreen->format->Bmask, Dummy_prSDLScreen->format->Amask); SDL_FreeSurface(Dummy_prSDLScreen); vc_dispmanx_display_get_info(dispmanxdisplay, &dispmanxdinfo); dispmanxresource_amigafb_1 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr); dispmanxresource_amigafb_2 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr); vc_dispmanx_rect_set(&blit_rect, 0, 0, width, height); vc_dispmanx_resource_write_data(dispmanxresource_amigafb_1, VC_IMAGE_RGB565, prSDLScreen->pitch, prSDLScreen->pixels, &blit_rect); vc_dispmanx_rect_set(&src_rect, 0, 0, width << 16, height << 16); // 16/9 to 4/3 ratio adaptation. if (currprefs.gfx_correct_aspect == 0 || screen_is_picasso) { // Fullscreen. int scaled_width = dispmanxdinfo.width * currprefs.gfx_fullscreen_ratio / 100; int scaled_height = dispmanxdinfo.height * currprefs.gfx_fullscreen_ratio / 100; vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width - scaled_width)/2, (dispmanxdinfo.height - scaled_height)/2, scaled_width, scaled_height); } else { // 4/3 shrink. int scaled_width = dispmanxdinfo.width * currprefs.gfx_fullscreen_ratio / 100; int scaled_height = dispmanxdinfo.height * currprefs.gfx_fullscreen_ratio / 100; vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width - scaled_width / 16 * 12)/2, (dispmanxdinfo.height - scaled_height)/2, scaled_width/16*12, scaled_height); } if (DispManXElementpresent == 0) { DispManXElementpresent = 1; dispmanxupdate = vc_dispmanx_update_start(0); dispmanxelement = vc_dispmanx_element_add(dispmanxupdate, dispmanxdisplay, 2, // layer &dst_rect, dispmanxresource_amigafb_1, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, DISPMANX_NO_ROTATE); vc_dispmanx_update_submit(dispmanxupdate, NULL, NULL); } uae_sem_post (&display_sem); break; case DISPLAY_SIGNAL_SHOW: if (current_resource_amigafb == 1) { current_resource_amigafb = 0; vc_dispmanx_resource_write_data(dispmanxresource_amigafb_1, VC_IMAGE_RGB565, adisplays.gfxvidinfo.drawbuffer.rowbytes, adisplays.gfxvidinfo.drawbuffer.bufmem, &blit_rect); dispmanxupdate = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(dispmanxupdate, dispmanxelement, dispmanxresource_amigafb_1); } else { current_resource_amigafb = 1; vc_dispmanx_resource_write_data(dispmanxresource_amigafb_2, VC_IMAGE_RGB565, adisplays.gfxvidinfo.drawbuffer.rowbytes, adisplays.gfxvidinfo.drawbuffer.bufmem, &blit_rect); dispmanxupdate = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(dispmanxupdate, dispmanxelement, dispmanxresource_amigafb_2); } vc_dispmanx_update_submit(dispmanxupdate, NULL, NULL); break; case DISPLAY_SIGNAL_QUIT: callback_registered = false; vc_dispmanx_vsync_callback(dispmanxdisplay, NULL, NULL); vc_dispmanx_display_close(dispmanxdisplay); bcm_host_deinit(); SDL_VideoQuit(); display_tid = 0; return 0; } } }
int process() { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T display_info; DISPMANX_RESOURCE_HANDLE_T screen_resource; VC_IMAGE_TRANSFORM_T transform; uint32_t image_prt; VC_RECT_T rect1; int ret; int fbfd = 0; char *fbp = 0; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; bcm_host_init(); display = vc_dispmanx_display_open(0); if (!display) { syslog(LOG_ERR, "Unable to open primary display"); return -1; } ret = vc_dispmanx_display_get_info(display, &display_info); if (ret) { syslog(LOG_ERR, "Unable to get primary display information"); return -1; } syslog(LOG_INFO, "Primary display is %d x %d", display_info.width, display_info.height); fbfd = open("/dev/fb1", O_RDWR); if (!fbfd) { syslog(LOG_ERR, "Unable to open secondary display"); return -1; } if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { syslog(LOG_ERR, "Unable to get secondary display information"); return -1; } if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { syslog(LOG_ERR, "Unable to get secondary display information"); return -1; } syslog(LOG_INFO, "Second display is %d x %d %dbps\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt); if (!screen_resource) { syslog(LOG_ERR, "Unable to create screen buffer"); close(fbfd); vc_dispmanx_display_close(display); return -1; } fbp = (char*) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if (fbp <= 0) { syslog(LOG_ERR, "Unable to create mamory mapping"); close(fbfd); ret = vc_dispmanx_resource_delete(screen_resource); vc_dispmanx_display_close(display); return -1; } vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres); while (1) { ret = vc_dispmanx_snapshot(display, screen_resource, 0); vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8); usleep(25 * 1000); } munmap(fbp, finfo.smem_len); close(fbfd); ret = vc_dispmanx_resource_delete(screen_resource); vc_dispmanx_display_close(display); }
int main(int argc, char *argv[]) { uint16_t background = 0x000F; int32_t layer = 1; uint32_t displayNumber = 0; int32_t xOffset = 0; int32_t yOffset = 0; uint32_t timeout = 0; bool xOffsetSet = false; bool yOffsetSet = false; bool interactive = true; program = basename(argv[0]); //--------------------------------------------------------------------- int opt = 0; while ((opt = getopt(argc, argv, "b:d:l:x:y:t:n")) != -1) { switch(opt) { case 'b': background = strtol(optarg, NULL, 16); break; case 'd': displayNumber = strtol(optarg, NULL, 10); break; case 'l': layer = strtol(optarg, NULL, 10); break; case 'x': xOffset = strtol(optarg, NULL, 10); xOffsetSet = true; break; case 'y': yOffset = strtol(optarg, NULL, 10); yOffsetSet = true; break; case 't': timeout = atoi(optarg); break; case 'n': interactive = false; break; default: usage(); break; } } //--------------------------------------------------------------------- if (optind >= argc) { usage(); } //--------------------------------------------------------------------- IMAGE_LAYER_T imageLayer; const char *imagePath = argv[optind]; if(strcmp(imagePath, "-") == 0) { // Use stdin if (loadPngFile(&(imageLayer.image), stdin) == false) { fprintf(stderr, "unable to load %s\n", imagePath); exit(EXIT_FAILURE); } } else { // Load image from path if (loadPng(&(imageLayer.image), imagePath) == false) { fprintf(stderr, "unable to load %s\n", imagePath); exit(EXIT_FAILURE); } } //--------------------------------------------------------------------- if (signal(SIGINT, signalHandler) == SIG_ERR) { perror("installing SIGINT signal handler"); exit(EXIT_FAILURE); } //--------------------------------------------------------------------- if (signal(SIGTERM, signalHandler) == SIG_ERR) { perror("installing SIGTERM signal handler"); exit(EXIT_FAILURE); } //--------------------------------------------------------------------- bcm_host_init(); //--------------------------------------------------------------------- DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(displayNumber); assert(display != 0); //--------------------------------------------------------------------- DISPMANX_MODEINFO_T info; int result = vc_dispmanx_display_get_info(display, &info); assert(result == 0); //--------------------------------------------------------------------- BACKGROUND_LAYER_T backgroundLayer; if (background > 0) { initBackgroundLayer(&backgroundLayer, background, 0); } createResourceImageLayer(&imageLayer, layer); //--------------------------------------------------------------------- DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); assert(update != 0); if (background > 0) { addElementBackgroundLayer(&backgroundLayer, display, update); } if (xOffsetSet == false) { xOffset = (info.width - imageLayer.image.width) / 2; } if (yOffsetSet == false) { yOffset = (info.height - imageLayer.image.height) / 2; } addElementImageLayerOffset(&imageLayer, xOffset, yOffset, display, update); result = vc_dispmanx_update_submit_sync(update); assert(result == 0); //--------------------------------------------------------------------- int32_t step = 1; uint32_t currentTime = 0; // Sleep for 10 milliseconds every run-loop const int sleepMilliseconds = 10; while (run) { int c = 0; if (interactive && keyPressed(&c)) { c = tolower(c); bool moveLayer = false; switch (c) { case 27: run = false; break; case 'a': xOffset -= step; moveLayer = true; break; case 'd': xOffset += step; moveLayer = true; break; case 'w': yOffset -= step; moveLayer = true; break; case 's': yOffset += step; moveLayer = true; break; case '+': if (step == 1) { step = 5; } else if (step == 5) { step = 10; } else if (step == 10) { step = 20; } break; case '-': if (step == 20) { step = 10; } else if (step == 10) { step = 5; } else if (step == 5) { step = 1; } break; } if (moveLayer) { update = vc_dispmanx_update_start(0); assert(update != 0); moveImageLayer(&imageLayer, xOffset, yOffset, update); result = vc_dispmanx_update_submit_sync(update); assert(result == 0); } } //--------------------------------------------------------------------- usleep(sleepMilliseconds * 1000); currentTime += sleepMilliseconds; if (timeout != 0 && currentTime >= timeout) { run = false; } } //--------------------------------------------------------------------- keyboardReset(); //--------------------------------------------------------------------- if (background > 0) { destroyBackgroundLayer(&backgroundLayer); } destroyImageLayer(&imageLayer); //--------------------------------------------------------------------- result = vc_dispmanx_display_close(display); assert(result == 0); //--------------------------------------------------------------------- return 0; }
int main( int argc, char *argv[]) { const char *program = basename(argv[0]); int fps = DEFAULT_FPS; suseconds_t frameDuration = 1000000 / fps; bool isDaemon = false; uint32_t sourceDisplayNumber = DEFAULT_SOURCE_DISPLAY_NUMBER; uint32_t destDisplayNumber = DEFAULT_DESTINATION_DISPLAY_NUMBER; int32_t layerNumber = DEFAULT_LAYER_NUMBER; const char *pidfile = NULL; //--------------------------------------------------------------------- static const char *sopts = "d:f:hl:p:s:D"; static struct option lopts[] = { { "destination", required_argument, NULL, 'd' }, { "fps", required_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, { "layer", required_argument, NULL, 'l' }, { "pidfile", required_argument, NULL, 'p' }, { "source", required_argument, NULL, 's' }, { "daemon", no_argument, NULL, 'D' }, { NULL, no_argument, NULL, 0 } }; int opt = 0; while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { switch (opt) { case 'd': destDisplayNumber = atoi(optarg); break; case 'f': fps = atoi(optarg); if (fps > 0) { frameDuration = 1000000 / fps; } else { fps = 1000000 / frameDuration; } break; case 'h': printUsage(stdout, program); exit(EXIT_SUCCESS); break; case 'l': layerNumber = atoi(optarg); break; case 'p': pidfile = optarg; break; case 's': sourceDisplayNumber = atoi(optarg); break; case 'D': isDaemon = true; break; default: printUsage(stderr, program); exit(EXIT_FAILURE); break; } } //--------------------------------------------------------------------- struct pidfh *pfh = NULL; if (isDaemon) { if (pidfile != NULL) { pid_t otherpid; pfh = pidfile_open(pidfile, 0600, &otherpid); if (pfh == NULL) { fprintf(stderr, "%s is already running %jd\n", program, (intmax_t)otherpid); exit(EXIT_FAILURE); } } if (daemon(0, 0) == -1) { fprintf(stderr, "daemonize failed\n"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } if (pfh) { pidfile_write(pfh); } openlog(program, LOG_PID, LOG_USER); } //--------------------------------------------------------------------- if (signal(SIGINT, signalHandler) == SIG_ERR) { perrorLog(isDaemon, program, "installing SIGINT signal handler"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } //--------------------------------------------------------------------- if (signal(SIGTERM, signalHandler) == SIG_ERR) { perrorLog(isDaemon, program, "installing SIGTERM signal handler"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } //--------------------------------------------------------------------- bcm_host_init(); //--------------------------------------------------------------------- int result = 0; //--------------------------------------------------------------------- // Make sure the VC_DISPLAY variable isn't set. unsetenv("VC_DISPLAY"); //--------------------------------------------------------------------- DISPMANX_DISPLAY_HANDLE_T sourceDisplay = vc_dispmanx_display_open(sourceDisplayNumber); if (sourceDisplay == 0) { messageLog(isDaemon, program, LOG_ERR, "open source display failed"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } DISPMANX_MODEINFO_T sourceInfo; result = vc_dispmanx_display_get_info(sourceDisplay, &sourceInfo); if (result != 0) { messageLog(isDaemon, program, LOG_ERR, "getting source display dimensions failed"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } //--------------------------------------------------------------------- DISPMANX_DISPLAY_HANDLE_T destDisplay = vc_dispmanx_display_open(destDisplayNumber); if (destDisplay == 0) { messageLog(isDaemon, program, LOG_ERR, "open destination display failed"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } DISPMANX_MODEINFO_T destInfo; result = vc_dispmanx_display_get_info(destDisplay, &destInfo); if (result != 0) { messageLog(isDaemon, program, LOG_ERR, "getting destination display dimensions failed"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } //--------------------------------------------------------------------- messageLog(isDaemon, program, LOG_INFO, "copying from [%d] %dx%d to [%d] %dx%d", sourceDisplayNumber, sourceInfo.width, sourceInfo.height, destDisplayNumber, destInfo.width, destInfo.height); //--------------------------------------------------------------------- uint32_t image_ptr; DISPMANX_RESOURCE_HANDLE_T resource = vc_dispmanx_resource_create(VC_IMAGE_RGBA32, destInfo.width, destInfo.height, &image_ptr); //--------------------------------------------------------------------- VC_RECT_T sourceRect; vc_dispmanx_rect_set(&sourceRect, 0, 0, destInfo.width << 16, destInfo.height << 16); VC_RECT_T destRect; vc_dispmanx_rect_set(&destRect, 0, 0, 0, 0); //--------------------------------------------------------------------- VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0 }; DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); if (update == 0) { messageLog(isDaemon, program, LOG_ERR, "display update failed"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } DISPMANX_ELEMENT_HANDLE_T element; element = vc_dispmanx_element_add(update, destDisplay, layerNumber, &destRect, resource, &sourceRect, DISPMANX_PROTECTION_NONE, &alpha, NULL, DISPMANX_NO_ROTATE); if (element == 0) { messageLog(isDaemon, program, LOG_ERR, "failed to create DispmanX element"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } vc_dispmanx_update_submit_sync(update); //--------------------------------------------------------------------- struct timeval start_time; struct timeval end_time; struct timeval elapsed_time; //--------------------------------------------------------------------- while (run) { gettimeofday(&start_time, NULL); //----------------------------------------------------------------- result = vc_dispmanx_snapshot(sourceDisplay, resource, DISPMANX_NO_ROTATE); if (result != 0) { messageLog(isDaemon, program, LOG_ERR, "DispmanX snapshot failed"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } //----------------------------------------------------------------- update = vc_dispmanx_update_start(0); if (update == 0) { messageLog(isDaemon, program, LOG_ERR, "display update failed"); exitAndRemovePidFile(EXIT_FAILURE, pfh); } vc_dispmanx_element_change_source(update, element, resource); vc_dispmanx_update_submit_sync(update); //----------------------------------------------------------------- gettimeofday(&end_time, NULL); timersub(&end_time, &start_time, &elapsed_time); if (elapsed_time.tv_sec == 0) { if (elapsed_time.tv_usec < frameDuration) { usleep(frameDuration - elapsed_time.tv_usec); } } } //--------------------------------------------------------------------- update = vc_dispmanx_update_start(0); vc_dispmanx_element_remove(update, element); vc_dispmanx_update_submit_sync(update); vc_dispmanx_resource_delete(resource); vc_dispmanx_display_close(sourceDisplay); vc_dispmanx_display_close(destDisplay); //--------------------------------------------------------------------- messageLog(isDaemon, program, LOG_INFO, "exiting"); if (isDaemon) { closelog(); } if (pfh) { pidfile_remove(pfh); } //--------------------------------------------------------------------- return 0 ; }