static void adjust_refresh_rate(vout_display_t *vd, const video_format_t *fmt) { vout_display_sys_t *sys = vd->sys; TV_DISPLAY_STATE_T display_state; TV_SUPPORTED_MODE_NEW_T supported_modes[VC_TV_MAX_MODE_IDS]; char response[20]; /* answer is hvs_update_fields=%1d */ int num_modes; double frame_rate = (double)fmt->i_frame_rate / fmt->i_frame_rate_base; int best_id = -1; double best_score, score; int i; vc_tv_get_display_state(&display_state); if(display_state.display.hdmi.mode != HDMI_MODE_OFF) { num_modes = vc_tv_hdmi_get_supported_modes_new(display_state.display.hdmi.group, supported_modes, VC_TV_MAX_MODE_IDS, NULL, NULL); for (i = 0; i < num_modes; ++i) { TV_SUPPORTED_MODE_NEW_T *mode = &supported_modes[i]; if (!sys->native_interlaced) { if (mode->width != display_state.display.hdmi.width || mode->height != display_state.display.hdmi.height || mode->scan_mode == HDMI_INTERLACED) continue; } else { if (mode->width != vd->fmt.i_visible_width || mode->height != vd->fmt.i_visible_height) continue; if (mode->scan_mode != sys->b_progressive ? HDMI_NONINTERLACED : HDMI_INTERLACED) continue; } score = fmod(supported_modes[i].frame_rate, frame_rate); if((best_id < 0) || (score < best_score)) { best_id = i; best_score = score; } } if((best_id >= 0) && (display_state.display.hdmi.mode != supported_modes[best_id].code)) { msg_Info(vd, "Setting HDMI refresh rate to %"PRIu32, supported_modes[best_id].frame_rate); vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, supported_modes[best_id].group, supported_modes[best_id].code); } if (sys->native_interlaced && supported_modes[best_id].scan_mode == HDMI_INTERLACED) { char hvs_mode = sys->b_top_field_first ? '1' : '2'; if (vc_gencmd(response, sizeof(response), "hvs_update_fields %c", hvs_mode) != 0 || response[18] != hvs_mode) msg_Warn(vd, "Could not set hvs field mode"); else msg_Info(vd, "Configured hvs field mode for interlaced %s playback", sys->b_top_field_first ? "tff" : "bff"); } } }
bool DisplayManagerRPI::setDisplayMode(int display, int mode) { if (!isValidDisplayMode(display, mode)) return false; HDMI_PROPERTY_PARAM_T property; property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE; property.param1 = (mode % 2) ? HDMI_PIXEL_CLOCK_TYPE_NTSC : HDMI_PIXEL_CLOCK_TYPE_PAL; property.param2 = 0; vc_tv_hdmi_set_property(&property); TV_SUPPORTED_MODE_NEW_T* tvmode = &m_modes[mode / 2]; bool ret = vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, (HDMI_RES_GROUP_T)tvmode->group, tvmode->code) == 0; if (!ret) { QLOG_ERROR() << "Failed to switch display mode" << ret; } return ret; }
/** * Return old mode so we can reset */ int rpi_set_display_framerate(float fps, int width, int height) { TV_DISPLAY_STATE_T state = {}; if(vc_tv_get_display_state(&state)) { TRACE(TRACE_DEBUG, "TV", "Failed to get TV state"); return -1; } TRACE(TRACE_DEBUG, "TV", "Searching for mode for %d x %d @ %f fps. Current mode=%d", width, height, fps, state.display.hdmi.mode); HDMI_RES_GROUP_T prefer_group; uint32_t prefer_mode; int native_deinterlace = 0; int num_modes = vc_tv_hdmi_get_supported_modes_new(HDMI_RES_GROUP_CEA, NULL, 0, &prefer_group, &prefer_mode); if(num_modes <= 0) return -1; TV_SUPPORTED_MODE_NEW_T *modes = alloca(sizeof(TV_SUPPORTED_MODE_NEW_T) * num_modes); num_modes = vc_tv_hdmi_get_supported_modes_new(HDMI_RES_GROUP_CEA, modes, num_modes, &prefer_group, &prefer_mode); TV_SUPPORTED_MODE_NEW_T *best_mode = NULL; uint32_t best_score = 1<<30; for(int i = 0; i < num_modes; i++) { TV_SUPPORTED_MODE_NEW_T *tv = modes + i; uint32_t score = 0; uint32_t w = tv->width; uint32_t h = tv->height; uint32_t r = tv->frame_rate; /* Check if frame rate match (equal or exact multiple) */ if(fabs(r - 1.0f*fps) / fps < 0.002f) score += 0; else if(fabs(r - 2.0f*fps) / fps < 0.002f) score += 1<<8; else score += (1<<16) + (1<<20)/r; // bad - but prefer higher framerate /* Check size too, only choose, bigger resolutions */ if(width && height) { /* cost of too small a resolution is high */ score += MAX((int)(width -w), 0) * (1<<16); score += MAX((int)(height-h), 0) * (1<<16); /* cost of too high a resolution is lower */ score += MAX((int)(w-width ), 0) * (1<<4); score += MAX((int)(h-height), 0) * (1<<4); } // native is good if (!tv->native) score += 1<<16; #if 0 // wanting 3D but not getting it is a negative if (is3d == CONF_FLAGS_FORMAT_SBS && !(tv->struct_3d_mask & HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL)) score += 1<<18; if (is3d == CONF_FLAGS_FORMAT_TB && !(tv->struct_3d_mask & HDMI_3D_STRUCT_TOP_AND_BOTTOM)) score += 1<<18; #endif // prefer square pixels modes float par = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio)*(float)tv->height/(float)tv->width; score += fabs(par - 1.0f) * (1<<12); if(score < best_score) { best_mode = tv; best_score = score; } } if(best_mode == NULL) return -1; char response[80]; TRACE(TRACE_DEBUG, "TV", "Output mode %d: %dx%d@%d %s%s:%x\n", best_mode->code, best_mode->width, best_mode->height, best_mode->frame_rate, best_mode->native ? "N":"", best_mode->scan_mode?"I":"", best_mode->code); if (native_deinterlace && best_mode->scan_mode) vc_gencmd(response, sizeof response, "hvs_update_fields %d", 1); // if we are closer to ntsc version of framerate, let gpu know int ifps = (int)(fps+0.5f); int ntsc_freq = fabs(fps*1001.0f/1000.0f - ifps) < fabs(fps-ifps); vc_gencmd(response, sizeof response, "hdmi_ntsc_freqs %d", ntsc_freq); /* Inform TV of any 3D settings. Note this property just applies to next hdmi mode change, so no need to call for 2D modes */ HDMI_PROPERTY_PARAM_T property; property.property = HDMI_PROPERTY_3D_STRUCTURE; property.param1 = HDMI_3D_FORMAT_NONE; property.param2 = 0; #if 0 if (is3d != CONF_FLAGS_FORMAT_NONE) { if (is3d == CONF_FLAGS_FORMAT_SBS && best_mode->struct_3d_mask & HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL) property.param1 = HDMI_3D_FORMAT_SBS_HALF; else if (is3d == CONF_FLAGS_FORMAT_TB && best_mode->struct_3d_mask & HDMI_3D_STRUCT_TOP_AND_BOTTOM) property.param1 = HDMI_3D_FORMAT_TB_HALF; m_BcmHost.vc_tv_hdmi_set_property(&property); } #endif TRACE(TRACE_DEBUG, "TV", "ntsc_freq:%d %s%s\n", ntsc_freq, property.param1 == HDMI_3D_FORMAT_SBS_HALF ? "3DSBS":"", property.param1 == HDMI_3D_FORMAT_TB_HALF ? "3DTB":""); int err = vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, HDMI_RES_GROUP_CEA, best_mode->code); if(err) { TRACE(TRACE_DEBUG, "TV", "Failed to set mode %d", best_mode->code); return -1; } return state.display.hdmi.mode; }
EGLNativeWindowType _glusCreateNativeWindowType(const char* title, const GLUSint width, const GLUSint height, const GLUSboolean fullscreen, const GLUSboolean noResize) { const SDL_VideoInfo* videoInfo; // DISPMANX_UPDATE_HANDLE_T dispmanUpdate; DISPMANX_ELEMENT_HANDLE_T dispmanElement; VC_RECT_T dstRect; VC_RECT_T srcRect; VC_DISPMANX_ALPHA_T dispmanAlpha; int32_t success; int32_t windowWidth; int32_t windowHeight; glusLogPrint(GLUS_LOG_INFO, "Parameters 'title' and 'noResize' are not used"); // Initialize graphics system bcm_host_init(); // Set fullscreen, if wanted if (fullscreen) { const uint32_t MAX_SUPPORTED_MODES = 128; HDMI_RES_GROUP_T group = HDMI_RES_GROUP_DMT; TV_SUPPORTED_MODE_NEW_T supportedModes[MAX_SUPPORTED_MODES]; int32_t i, numberSupportedModes; numberSupportedModes = vc_tv_hdmi_get_supported_modes_new(group, supportedModes, MAX_SUPPORTED_MODES, 0, 0); for (i = 0; i < numberSupportedModes; i++) { if (supportedModes[i].width == (uint32_t)width && supportedModes[i].height == (uint32_t)height && supportedModes[i].frame_rate >= 60) { break; } } if (i == numberSupportedModes) { glusLogPrint(GLUS_LOG_ERROR, "No matching display resolution found: ", width, height); return EGL_NO_SURFACE ; } vc_tv_register_callback(resizeDone, 0); if (vc_tv_hdmi_power_on_explicit_new(group, supportedModes[i].group, supportedModes[i].code) != 0) { vc_tv_unregister_callback(resizeDone); glusLogPrint(GLUS_LOG_ERROR, "Could not switch to full screen: ", width, height); return EGL_NO_SURFACE ; } waitResizeDone(); vc_tv_unregister_callback(resizeDone); windowWidth = width; windowHeight = height; _fullscreen = GLUS_TRUE; } else { windowWidth = width; windowHeight = height; } // _nativeDisplay = vc_dispmanx_display_open(0 /* LCD */); if (!_nativeDisplay) { glusLogPrint(GLUS_LOG_ERROR, "Could not open display"); return EGL_NO_SURFACE ; } // if (SDL_Init(SDL_INIT_VIDEO) != 0) { glusLogPrint(GLUS_LOG_ERROR, "Could not initialize SDL"); return EGL_NO_SURFACE ; } videoInfo = SDL_GetVideoInfo(); if (!videoInfo) { glusLogPrint(GLUS_LOG_ERROR, "Could not get video info for SDL"); return EGL_NO_SURFACE ; } if (!SDL_SetVideoMode(videoInfo->current_w, videoInfo->current_h, videoInfo->vfmt->BitsPerPixel, SDL_HWSURFACE)) { glusLogPrint(GLUS_LOG_ERROR, "Set video mode for SDL failed"); return EGL_NO_SURFACE ; } SDL_ShowCursor(SDL_DISABLE); // dstRect.x = 0; dstRect.y = 0; dstRect.width = windowWidth; dstRect.height = windowHeight; srcRect.x = 0; srcRect.y = 0; srcRect.width = windowWidth << 16; srcRect.height = windowHeight << 16; dispmanAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; dispmanAlpha.mask = 0xFFFFFFFF; dispmanAlpha.opacity = 255; dispmanUpdate = vc_dispmanx_update_start(0); dispmanElement = vc_dispmanx_element_add(dispmanUpdate, _nativeDisplay, 0 /*layer*/, &dstRect, 0 /*src*/, &srcRect, DISPMANX_PROTECTION_NONE, &dispmanAlpha, 0/*clamp*/, 0/*transform*/); success = vc_dispmanx_update_submit_sync(dispmanUpdate); if (!dispmanElement || success < 0) { glusLogPrint(GLUS_LOG_ERROR, "Could not add element"); return EGL_NO_SURFACE ; } _width = windowWidth; _height = windowHeight; _nativeWindow.element = dispmanElement; _nativeWindow.width = windowWidth; _nativeWindow.height = windowHeight; _nativeWindowCreated = GLUS_TRUE; return (EGLNativeWindowType)&_nativeWindow; }