Пример #1
0
static int get_status( void )
{
   TV_DISPLAY_STATE_T tvstate;
   if( vc_tv_get_display_state( &tvstate ) == 0) {
      //The width/height parameters are in the same position in the union
      //for HDMI and SDTV
      HDMI_PROPERTY_PARAM_T property;
      property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
      vc_tv_hdmi_get_property(&property);
      float frame_rate = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? tvstate.display.hdmi.frame_rate * (1000.0f/1001.0f) : tvstate.display.hdmi.frame_rate;

      if(tvstate.display.hdmi.width && tvstate.display.hdmi.height) {
         LOG_STD( "state 0x%x [%s], %ux%u @ %.2fHz, %s", tvstate.state,
                  status_mode(&tvstate),
                  tvstate.display.hdmi.width, tvstate.display.hdmi.height,
                  frame_rate,
                  tvstate.display.hdmi.scan_mode ? "interlaced" : "progressive" );
      } else {
         LOG_STD( "state 0x%x [%s]", tvstate.state, status_mode(&tvstate));
      }
   } else {
      LOG_STD( "Error getting current display state");
   }
  return 0;
}
int DisplayManagerRPI::getCurrentDisplayMode(int display)
{
  if (!isValidDisplay(display))
    return -1;

  TV_GET_STATE_RESP_T tvstate;
  if (vc_tv_get_state(&tvstate))
    return -1;

  for (int mode = 0; mode < m_displays[display]->m_videoModes.size(); mode++)
  {
    TV_SUPPORTED_MODE_NEW_T* tvmode = &m_modes[mode];
    if (tvmode->width == tvstate.width &&
        tvmode->height == tvstate.height &&
        tvmode->frame_rate == tvstate.frame_rate &&
        tvmode->scan_mode == tvstate.scan_mode)
    {
      bool ntsc = false;
      HDMI_PROPERTY_PARAM_T property;
      property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
      property.param1 = 0;
      property.param2 = 0;
      if (!vc_tv_hdmi_get_property(&property))
        ntsc = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC;
      return mode * 2 + (ntsc ? 1 : 0);
    }
  }

  return -1;
}
Пример #3
0
int graphics_setup(void)
{
#ifdef PICASSO96
	picasso_InitResolutions();
	InitPicasso96();
#endif
  VCHI_INSTANCE_T vchi_instance;
  VCHI_CONNECTION_T *vchi_connection;
  TV_DISPLAY_STATE_T tvstate;

  if(vchi_initialise(&vchi_instance) == 0) {
    if(vchi_connect(NULL, 0, vchi_instance) == 0) {
      vc_vchi_tv_init(vchi_instance, &vchi_connection, 1);
      if(vc_tv_get_display_state(&tvstate) == 0) {
        HDMI_PROPERTY_PARAM_T property;
        property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
        vc_tv_hdmi_get_property(&property);
        float frame_rate = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? tvstate.display.hdmi.frame_rate * (1000.0f/1001.0f) : tvstate.display.hdmi.frame_rate;
        host_hz = (int)frame_rate;
        time_per_host_frame = time_for_host_hz_frames / host_hz;
      }
      vc_vchi_tv_stop();
      vchi_disconnect(vchi_instance);
    }
  }

  if(display_pipe == 0) {
    display_pipe = xmalloc (smp_comm_pipe, 1);
    init_comm_pipe(display_pipe, 20, 1);
  }
  if(display_sem == 0) {
    uae_sem_init (&display_sem, 0, 0);
  }
  if(display_tid == 0 && display_pipe != 0 && display_sem != 0) {
    uae_start_thread(_T("render"), display_thread, NULL, &display_tid);
  }
	write_comm_pipe_u32(display_pipe, DISPLAY_SIGNAL_SETUP, 1);
	
	return 1;
}
Пример #4
0
bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
{
#if defined(TARGET_RASPBERRY_PI)
  resolutions.clear();

  if(!m_DllBcmHost)
    return false;

  /* read initial desktop resolution before probe resolutions.
   * probing will replace the desktop resolution when it finds the same one.
   * we raplace it because probing will generate more detailed 
   * resolution flags we don't get with vc_tv_get_state.
   */

  if(m_initDesktopRes)
  {
    TV_DISPLAY_STATE_T tv_state;

    // get current display settings state
    memset(&tv_state, 0, sizeof(TV_DISPLAY_STATE_T));
    m_DllBcmHost->vc_tv_get_display_state(&tv_state);

    if ((tv_state.state & ( VC_HDMI_HDMI | VC_HDMI_DVI )) != 0) // hdtv
    {
      m_desktopRes.iScreen      = 0;
      m_desktopRes.bFullScreen  = true;
      m_desktopRes.iWidth       = tv_state.display.hdmi.width;
      m_desktopRes.iHeight      = tv_state.display.hdmi.height;
      m_desktopRes.iScreenWidth = tv_state.display.hdmi.width;
      m_desktopRes.iScreenHeight= tv_state.display.hdmi.height;
      m_desktopRes.dwFlags      = MAKEFLAGS(tv_state.display.hdmi.group, tv_state.display.hdmi.mode, tv_state.display.hdmi.scan_mode);
      m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
      HDMI_PROPERTY_PARAM_T property;
      property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
      vc_tv_hdmi_get_property(&property);
      m_desktopRes.fRefreshRate = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? tv_state.display.hdmi.frame_rate * (1000.0f/1001.0f) : tv_state.display.hdmi.frame_rate;
    }
    else if ((tv_state.state & ( VC_SDTV_NTSC | VC_SDTV_PAL )) != 0) // sdtv
    {
      m_desktopRes.iScreen      = 0;
      m_desktopRes.bFullScreen  = true;
      m_desktopRes.iWidth       = tv_state.display.sdtv.width;
      m_desktopRes.iHeight      = tv_state.display.sdtv.height;
      m_desktopRes.iScreenWidth = tv_state.display.sdtv.width;
      m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
      m_desktopRes.dwFlags      = MAKEFLAGS(HDMI_RES_GROUP_INVALID, tv_state.display.sdtv.mode, 1);
      m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
      m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
    }
    else if ((tv_state.state & VC_LCD_ATTACHED_DEFAULT) != 0) // lcd
    {
      m_desktopRes.iScreen      = 0;
      m_desktopRes.bFullScreen  = true;
      m_desktopRes.iWidth       = tv_state.display.sdtv.width;
      m_desktopRes.iHeight      = tv_state.display.sdtv.height;
      m_desktopRes.iScreenWidth = tv_state.display.sdtv.width;
      m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
      m_desktopRes.dwFlags      = MAKEFLAGS(HDMI_RES_GROUP_INVALID, 0, 0);
      m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
      m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
    }

    SetResolutionString(m_desktopRes);

    m_initDesktopRes = false;

    m_desktopRes.iSubtitles   = (int)(0.965 * m_desktopRes.iHeight);

    CLog::Log(LOGDEBUG, "EGL initial desktop resolution %s (%.2f)\n", m_desktopRes.strMode.c_str(), m_desktopRes.fPixelRatio);
  }

  if(GETFLAGS_GROUP(m_desktopRes.dwFlags) && GETFLAGS_MODE(m_desktopRes.dwFlags))
  {
    GetSupportedModes(HDMI_RES_GROUP_DMT, resolutions);
    GetSupportedModes(HDMI_RES_GROUP_CEA, resolutions);
  }
  {
    AddUniqueResolution(m_desktopRes, resolutions, true);
    CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
  }

  DLOG("CEGLNativeTypeRaspberryPI::ProbeResolutions\n");
  return true;
#else
  return false;
#endif
}
Пример #5
0
static bool recreate_dispmanx(struct ra_ctx *ctx)
{
    struct priv *p = ctx->priv;
    int display_nr = 0;
    int layer = 0;

    MP_VERBOSE(ctx, "Recreating DISPMANX state...\n");

    destroy_dispmanx(ctx);

    p->display = vc_dispmanx_display_open(display_nr);
    p->update = vc_dispmanx_update_start(0);
    if (!p->display || !p->update) {
        MP_FATAL(ctx, "Could not get DISPMANX objects.\n");
        goto fail;
    }

    uint32_t dispw, disph;
    if (graphics_get_display_size(0, &dispw, &disph) < 0) {
        MP_FATAL(ctx, "Could not get display size.\n");
        goto fail;
    }
    p->w = dispw;
    p->h = disph;

    if (ctx->vo->opts->fullscreen) {
        p->x = p->y = 0;
    } else {
        struct vo_win_geometry geo;
        struct mp_rect screenrc = {0, 0, p->w, p->h};

        vo_calc_window_geometry(ctx->vo, &screenrc, &geo);

        mp_rect_intersection(&geo.win, &screenrc);

        p->x = geo.win.x0;
        p->y = geo.win.y0;
        p->w = geo.win.x1 - geo.win.x0;
        p->h = geo.win.y1 - geo.win.y0;
    }

    // dispmanx is like a neanderthal version of Wayland - you can add an
    // overlay any place on the screen.
    VC_RECT_T dst = {.x = p->x, .y = p->y, .width = p->w, .height = p->h};
    VC_RECT_T src = {.width = p->w << 16, .height = p->h << 16};
    VC_DISPMANX_ALPHA_T alpha = {
        .flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE,
        .opacity = 0xFF,
    };
    p->window = vc_dispmanx_element_add(p->update, p->display, layer, &dst, 0,
                                        &src, DISPMANX_PROTECTION_NONE, &alpha,
                                        0, 0);
    if (!p->window) {
        MP_FATAL(ctx, "Could not add DISPMANX element.\n");
        goto fail;
    }

    vc_dispmanx_update_submit_sync(p->update);
    p->update = vc_dispmanx_update_start(0);

    p->egl_window = (EGL_DISPMANX_WINDOW_T){
        .element = p->window,
        .width = p->w,
        .height = p->h,
    };
    p->egl_surface = eglCreateWindowSurface(p->egl_display, p->egl_config,
                                            &p->egl_window, NULL);

    if (p->egl_surface == EGL_NO_SURFACE) {
        MP_FATAL(ctx, "Could not create EGL surface!\n");
        goto fail;
    }

    if (!eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface,
                        p->egl_context))
    {
        MP_FATAL(ctx, "Failed to set context!\n");
        goto fail;
    }

    p->display_fps = 0;
    TV_GET_STATE_RESP_T tvstate;
    TV_DISPLAY_STATE_T tvstate_disp;
    if (!vc_tv_get_state(&tvstate) && !vc_tv_get_display_state(&tvstate_disp)) {
        if (tvstate_disp.state & (VC_HDMI_HDMI | VC_HDMI_DVI)) {
            p->display_fps = tvstate_disp.display.hdmi.frame_rate;

            HDMI_PROPERTY_PARAM_T param = {
                .property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE,
            };
            if (!vc_tv_hdmi_get_property(&param) &&
                param.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC)
                p->display_fps = p->display_fps / 1.001;
        } else {
            p->display_fps = tvstate_disp.display.sdtv.frame_rate;
        }
    }

    p->win_params[0] = display_nr;
    p->win_params[1] = layer;
    p->win_params[2] = p->x;
    p->win_params[3] = p->y;

    ctx->vo->dwidth = p->w;
    ctx->vo->dheight = p->h;
    ra_gl_ctx_resize(ctx->swapchain, p->w, p->h, 0);

    ctx->vo->want_redraw = true;

    vo_event(ctx->vo, VO_EVENT_WIN_STATE);
    return true;

fail:
    destroy_dispmanx(ctx);
    return false;
}

static void rpi_swap_buffers(struct ra_ctx *ctx)
{
    struct priv *p = ctx->priv;
    eglSwapBuffers(p->egl_display, p->egl_surface);
}

static bool rpi_init(struct ra_ctx *ctx)
{
    struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);

    bcm_host_init();

    vc_tv_register_callback(tv_callback, ctx);

    p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (!eglInitialize(p->egl_display, NULL, NULL)) {
        MP_FATAL(ctx, "EGL failed to initialize.\n");
        goto fail;
    }

    if (!mpegl_create_context(ctx, p->egl_display, &p->egl_context, &p->egl_config))
        goto fail;

    if (recreate_dispmanx(ctx) < 0)
        goto fail;

    mpegl_load_functions(&p->gl, ctx->log);

    struct ra_gl_ctx_params params = {
        .swap_buffers = rpi_swap_buffers,
        .native_display_type = "MPV_RPI_WINDOW",
        .native_display = p->win_params,
    };

    if (!ra_gl_ctx_init(ctx, &p->gl, params))
        goto fail;

    return true;

fail:
    rpi_uninit(ctx);
    return false;
}

static bool rpi_reconfig(struct ra_ctx *ctx)
{
    return recreate_dispmanx(ctx);
}

static struct mp_image *take_screenshot(struct ra_ctx *ctx)
{
    struct priv *p = ctx->priv;

    if (!p->display)
        return NULL;

    struct mp_image *img = mp_image_alloc(IMGFMT_BGR0, p->w, p->h);
    if (!img)
        return NULL;

    DISPMANX_RESOURCE_HANDLE_T resource =
        vc_dispmanx_resource_create(VC_IMAGE_ARGB8888,
                                    img->w | ((img->w * 4) << 16), img->h,
                                    &(int32_t){0});
    if (!resource)
        goto fail;

    if (vc_dispmanx_snapshot(p->display, resource, 0))
        goto fail;

    VC_RECT_T rc = {.width = img->w, .height = img->h};
    if (vc_dispmanx_resource_read_data(resource, &rc, img->planes[0], img->stride[0]))
        goto fail;

    vc_dispmanx_resource_delete(resource);
    return img;

fail:
    vc_dispmanx_resource_delete(resource);
    talloc_free(img);
    return NULL;
}

static int rpi_control(struct ra_ctx *ctx, int *events, int request, void *arg)
{
    struct priv *p = ctx->priv;

    switch (request) {
    case VOCTRL_SCREENSHOT_WIN:
        *(struct mp_image **)arg = take_screenshot(ctx);
        return VO_TRUE;
    case VOCTRL_FULLSCREEN:
        recreate_dispmanx(ctx);
        return VO_TRUE;
    case VOCTRL_CHECK_EVENTS:
        if (atomic_fetch_and(&p->reload_display, 0)) {
            MP_WARN(ctx, "Recovering from display mode switch...\n");
            recreate_dispmanx(ctx);
        }
        return VO_TRUE;
    case VOCTRL_GET_DISPLAY_FPS:
        *(double *)arg = p->display_fps;
        return VO_TRUE;
    }

    return VO_NOTIMPL;
}

const struct ra_ctx_fns ra_ctx_rpi = {
    .type           = "opengl",
    .name           = "rpi",
    .reconfig       = rpi_reconfig,
    .control        = rpi_control,
    .init           = rpi_init,
    .uninit         = rpi_uninit,
};