Exemplo n.º 1
0
static void gfx_ctx_vc_swap_buffers(void *data, void *data2)
{
#ifdef HAVE_EGL
   vc_ctx_data_t              *vc = (vc_ctx_data_t*)data;
   video_frame_info_t *video_info = (video_frame_info_t*)data2;

   if (!vc)
      return;

   egl_swap_buffers(&vc->egl);

   /* Wait for vsync immediately if we don't 
    * want egl_swap_buffers to triple-buffer */
   if (video_info->max_swapchain_images <= 2)
   {
      /* We DON'T wait to wait without callback function ready! */
      if (!vc->vsync_callback_set)
      {
         vc_dispmanx_vsync_callback(vc->dispman_display,
               dispmanx_vsync_callback, (void*)vc);
         vc->vsync_callback_set = true;
      }
      slock_lock(vc->vsync_condition_mutex);
      scond_wait(vc->vsync_condition, vc->vsync_condition_mutex);
      slock_unlock(vc->vsync_condition_mutex);
   }
   /* Stop generating vsync callbacks from now on */
   else if (vc->vsync_callback_set)
      vc_dispmanx_vsync_callback(vc->dispman_display, NULL, NULL);
#endif
}
Exemplo n.º 2
0
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;
    }
  }
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
static void gfx_ctx_vc_destroy(void *data)
{
   vc_ctx_data_t *vc = (vc_ctx_data_t*)data;
   unsigned i;

   if (!vc)
   {
       g_egl_inited = false;
       return;
   }

   if (vc->egl.dpy)
   {
      for (i = 0; i < MAX_EGLIMAGE_TEXTURES; i++)
      {
         if (vc->eglBuffer[i] && peglDestroyImageKHR)
         {
            eglBindAPI(EGL_OPENVG_API);
            eglMakeCurrent(vc->egl.dpy,
                  vc->pbuff_surf, vc->pbuff_surf, vc->eglimage_ctx);
            peglDestroyImageKHR(vc->egl.dpy, vc->eglBuffer[i]);
         }

         if (vc->vgimage[i])
         {
            eglBindAPI(EGL_OPENVG_API);
            eglMakeCurrent(vc->egl.dpy,
                  vc->pbuff_surf, vc->pbuff_surf, vc->eglimage_ctx);
            vgDestroyImage(vc->vgimage[i]);
         }
      }

      if (vc->egl.ctx)
      {
         gfx_ctx_vc_bind_api(data, vc_api, 0, 0);
         eglMakeCurrent(vc->egl.dpy,
               EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
         eglDestroyContext(vc->egl.dpy, vc->egl.ctx);
      }

      if (vc->egl.hw_ctx)
         eglDestroyContext(vc->egl.dpy, vc->egl.hw_ctx);

      if (vc->eglimage_ctx)
      {
         eglBindAPI(EGL_OPENVG_API);
         eglMakeCurrent(vc->egl.dpy,
               EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
         eglDestroyContext(vc->egl.dpy, vc->eglimage_ctx);
      }

      if (vc->egl.surf)
      {
         gfx_ctx_vc_bind_api(data, vc_api, 0, 0);
         eglDestroySurface(vc->egl.dpy, vc->egl.surf);
      }

      if (vc->pbuff_surf)
      {
         eglBindAPI(EGL_OPENVG_API);
         eglDestroySurface(vc->egl.dpy, vc->pbuff_surf);
      }

      eglBindAPI(EGL_OPENVG_API);
      eglMakeCurrent(vc->egl.dpy,
            EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
      gfx_ctx_vc_bind_api(data, vc_api, 0, 0);
      eglMakeCurrent(vc->egl.dpy,
            EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
      eglTerminate(vc->egl.dpy);
   }

   vc->egl.ctx      = NULL;
   vc->egl.hw_ctx   = NULL;
   vc->eglimage_ctx = NULL;
   vc->egl.surf     = NULL;
   vc->pbuff_surf   = NULL;
   vc->egl.dpy      = NULL;
   vc->egl.config   = 0;
   g_egl_inited     = false;

   for (i = 0; i < MAX_EGLIMAGE_TEXTURES; i++)
   {
      vc->eglBuffer[i] = NULL;
      vc->vgimage[i]   = 0;
   }

   /* Stop generating vsync callbacks if we are doing so. 
    * Don't destroy the context while cbs are being generated! */
   if (vc->vsync_callback_set)
      vc_dispmanx_vsync_callback(vc->dispman_display, NULL, NULL);

   /* Destroy mutexes and conditions. */
   slock_free(vc->vsync_condition_mutex);
   scond_free(vc->vsync_condition);
}
Exemplo n.º 5
0
int main(int argc, char *argv[])
{
    int ret;
    VC_RECT_T       src_rect;
    VC_RECT_T       dst_rect;

    DISPMANX_UPDATE_HANDLE_T    update;
    uint32_t                    vc_image_ptr;

    bcm_host_init();

    display = vc_dispmanx_display_open( 0 );

    image = calloc( 1, PITCH * HEIGHT ); // buffer 0
    assert(image);

    // initialize image buffer with clock run in
    int n, m, clock = 0x275555;
    for (m=0; m<24; m++) {
        for (n=0; n<HEIGHT; n++) {
            ROW(n)[m] = clock&1;
        }
        clock = clock >> 1;
    }

    // fill up image with filler packets
    // get_packet will return filler because we haven't loaded the fifo yet.
    get_packet(ROW(0)+24);
    for (n=1; n<HEIGHT; n++) {
        memcpy(ROW(n)+24, ROW(0)+24, 336);
    }

    // set up some resources
    vc_dispmanx_rect_set( &image_rect, 0, 0, WIDTH, HEIGHT);
    for (n=0;n<3;n++) {
        resource[n] = vc_dispmanx_resource_create( TYPE, WIDTH, HEIGHT, &vc_image_ptr );
        assert( resource[n] );
        ret = vc_dispmanx_resource_set_palette(  resource[n], palette, 0, sizeof palette );
        assert( ret == 0 );
        ret = vc_dispmanx_resource_write_data(  resource[n], TYPE, PITCH, image, &image_rect );
        assert( ret == 0 );
    }
    vc_dispmanx_rect_set( &image_rect, OFFSET+24, 0, 336, HEIGHT); // from now on, only copy the parts that change

    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, 0, 720, HEIGHT );
    element = vc_dispmanx_element_add( update, display, 2000,
                                       &dst_rect, resource[2], &src_rect,
                                       DISPMANX_PROTECTION_NONE,
                                       NULL, NULL, VC_IMAGE_ROT0 );

    ret = vc_dispmanx_update_submit_sync( update );
    assert( ret == 0 );

    // BUG: clear any existing callbacks, even to other apps.
    // https://github.com/raspberrypi/userland/issues/218
    vc_dispmanx_vsync_callback(display, NULL, NULL);

    vc_dispmanx_vsync_callback(display, vsync, NULL);

    if (argc == 2 && argv[1][0] == '-') {
        while(read_packets()) {
            ;
        }
    } else {
        demo();
    }

    vc_dispmanx_vsync_callback(display, NULL, NULL); // disable callback

    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 );
    for (n=0; n<3; n++) {
        ret = vc_dispmanx_resource_delete( resource[0] );
        assert( ret == 0 );
    }
    ret = vc_dispmanx_display_close( display );
    assert( ret == 0 );

    return 0;
}