int RPI_CreateWindow(_THIS, SDL_Window * window) { SDL_WindowData *wdata; SDL_VideoDisplay *display; SDL_DisplayData *displaydata; VC_RECT_T dst_rect; VC_RECT_T src_rect; VC_DISPMANX_ALPHA_T dispman_alpha; DISPMANX_UPDATE_HANDLE_T dispman_update; /* Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc) */ dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; dispman_alpha.opacity = 0xFF; dispman_alpha.mask = 0; /* Allocate window internal data */ wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); if (wdata == NULL) { return SDL_OutOfMemory(); } display = SDL_GetDisplayForWindow(window); displaydata = (SDL_DisplayData *) display->driverdata; /* Windows have one size for now */ window->w = display->desktop_mode.w; window->h = display->desktop_mode.h; /* OpenGL ES is the law here, buddy */ window->flags |= SDL_WINDOW_OPENGL; /* Create a dispman element and associate a window to it */ dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = window->w; dst_rect.height = window->h; src_rect.x = 0; src_rect.y = 0; src_rect.width = window->w << 16; src_rect.height = window->h << 16; dispman_update = vc_dispmanx_update_start( 0 ); wdata->dispman_window.element = vc_dispmanx_element_add ( dispman_update, displaydata->dispman_display, SDL_RPI_VIDEOLAYER /* layer */, &dst_rect, 0/*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &dispman_alpha /*alpha*/, 0/*clamp*/, 0/*transform*/); wdata->dispman_window.width = window->w; wdata->dispman_window.height = window->h; vc_dispmanx_update_submit_sync( dispman_update ); if (!_this->egl_data) { if (SDL_GL_LoadLibrary(NULL) < 0) { return -1; } } wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) &wdata->dispman_window); if (wdata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); } /* Setup driver data for this window */ window->driverdata = wdata; /* One window, it always has focus */ SDL_SetMouseFocus(window); SDL_SetKeyboardFocus(window); /* Window has been successfully created */ return 0; }
void GlContext::create(uint32_t _width, uint32_t _height) { # if BX_PLATFORM_RPI bcm_host_init(); # endif // BX_PLATFORM_RPI m_eglLibrary = eglOpen(); if (NULL == g_platformData.context) { # if BX_PLATFORM_RPI g_platformData.ndt = EGL_DEFAULT_DISPLAY; # endif // BX_PLATFORM_RPI BX_UNUSED(_width, _height); EGLNativeDisplayType ndt = (EGLNativeDisplayType)g_platformData.ndt; EGLNativeWindowType nwh = (EGLNativeWindowType )g_platformData.nwh; # if BX_PLATFORM_WINDOWS if (NULL == g_platformData.ndt) { ndt = GetDC( (HWND)g_platformData.nwh); } # endif // BX_PLATFORM_WINDOWS m_display = eglGetDisplay(ndt); BGFX_FATAL(m_display != EGL_NO_DISPLAY, Fatal::UnableToInitialize, "Failed to create display %p", m_display); EGLint major = 0; EGLint minor = 0; EGLBoolean success = eglInitialize(m_display, &major, &minor); BGFX_FATAL(success && major >= 1 && minor >= 3, Fatal::UnableToInitialize, "Failed to initialize %d.%d", major, minor); BX_TRACE("EGL info:"); const char* clientApis = eglQueryString(m_display, EGL_CLIENT_APIS); BX_TRACE(" APIs: %s", clientApis); BX_UNUSED(clientApis); const char* vendor = eglQueryString(m_display, EGL_VENDOR); BX_TRACE(" Vendor: %s", vendor); BX_UNUSED(vendor); const char* version = eglQueryString(m_display, EGL_VERSION); BX_TRACE("Version: %s", version); BX_UNUSED(version); const char* extensions = eglQueryString(m_display, EGL_EXTENSIONS); BX_TRACE("Supported EGL extensions:"); dumpExtensions(extensions); EGLint attrs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, # if BX_PLATFORM_ANDROID EGL_DEPTH_SIZE, 16, # else EGL_DEPTH_SIZE, 24, # endif // BX_PLATFORM_ EGL_STENCIL_SIZE, 8, EGL_NONE }; EGLint numConfig = 0; success = eglChooseConfig(m_display, attrs, &m_config, 1, &numConfig); BGFX_FATAL(success, Fatal::UnableToInitialize, "eglChooseConfig"); # if BX_PLATFORM_ANDROID EGLint format; eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &format); ANativeWindow_setBuffersGeometry( (ANativeWindow*)g_platformData.nwh, _width, _height, format); # elif BX_PLATFORM_RPI DISPMANX_DISPLAY_HANDLE_T dispmanDisplay = vc_dispmanx_display_open(0); DISPMANX_UPDATE_HANDLE_T dispmanUpdate = vc_dispmanx_update_start(0); VC_RECT_T dstRect = { 0, 0, int32_t(_width), int32_t(_height) }; VC_RECT_T srcRect = { 0, 0, int32_t(_width) << 16, int32_t(_height) << 16 }; DISPMANX_ELEMENT_HANDLE_T dispmanElement = vc_dispmanx_element_add(dispmanUpdate , dispmanDisplay , 0 , &dstRect , 0 , &srcRect , DISPMANX_PROTECTION_NONE , NULL , NULL , DISPMANX_NO_ROTATE ); s_dispmanWindow.element = dispmanElement; s_dispmanWindow.width = _width; s_dispmanWindow.height = _height; nwh = &s_dispmanWindow; vc_dispmanx_update_submit_sync(dispmanUpdate); # endif // BX_PLATFORM_ANDROID m_surface = eglCreateWindowSurface(m_display, m_config, nwh, NULL); BGFX_FATAL(m_surface != EGL_NO_SURFACE, Fatal::UnableToInitialize, "Failed to create surface."); const bool hasEglKhrCreateContext = !!bx::findIdentifierMatch(extensions, "EGL_KHR_create_context"); const bool hasEglKhrNoError = !!bx::findIdentifierMatch(extensions, "EGL_KHR_create_context_no_error"); const uint32_t gles = BGFX_CONFIG_RENDERER_OPENGLES; for (uint32_t ii = 0; ii < 2; ++ii) { bx::StaticMemoryBlockWriter writer(s_contextAttrs, sizeof(s_contextAttrs) ); EGLint flags = 0; # if BX_PLATFORM_RPI BX_UNUSED(hasEglKhrCreateContext, hasEglKhrNoError); # else if (hasEglKhrCreateContext) { bx::write(&writer, EGLint(EGL_CONTEXT_MAJOR_VERSION_KHR) ); bx::write(&writer, EGLint(gles / 10) ); bx::write(&writer, EGLint(EGL_CONTEXT_MINOR_VERSION_KHR) ); bx::write(&writer, EGLint(gles % 10) ); flags |= BGFX_CONFIG_DEBUG && hasEglKhrNoError ? 0 | EGL_CONTEXT_FLAG_NO_ERROR_BIT_KHR : 0 ; if (0 == ii) { flags |= BGFX_CONFIG_DEBUG ? 0 | EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR // | EGL_OPENGL_ES3_BIT_KHR : 0 ; bx::write(&writer, EGLint(EGL_CONTEXT_FLAGS_KHR) ); bx::write(&writer, flags); } } else # endif // BX_PLATFORM_RPI { bx::write(&writer, EGLint(EGL_CONTEXT_CLIENT_VERSION) ); bx::write(&writer, 2); } bx::write(&writer, EGLint(EGL_NONE) ); m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, s_contextAttrs); if (NULL != m_context) { break; } BX_TRACE("Failed to create EGL context with EGL_CONTEXT_FLAGS_KHR (%08x).", flags); } BGFX_FATAL(m_context != EGL_NO_CONTEXT, Fatal::UnableToInitialize, "Failed to create context."); success = eglMakeCurrent(m_display, m_surface, m_surface, m_context); BGFX_FATAL(success, Fatal::UnableToInitialize, "Failed to set context."); m_current = NULL; eglSwapInterval(m_display, 0); } import(); g_internalData.context = m_context; }
/* Show the specified cursor, or hide if cursor is NULL */ static int RPI_ShowCursor(SDL_Cursor * cursor) { int ret; DISPMANX_UPDATE_HANDLE_T update; RPI_CursorData *curdata; VC_RECT_T src_rect, dst_rect; SDL_Mouse *mouse; SDL_VideoDisplay *display; SDL_DisplayData *data; VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/, 0 /* mask */ }; mouse = SDL_GetMouse(); if (mouse == NULL) { return -1; } if (cursor == NULL) { /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */ if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) { curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata; if (curdata->element > DISPMANX_NO_HANDLE) { update = vc_dispmanx_update_start( 10 ); SDL_assert( update ); ret = vc_dispmanx_element_remove( update, curdata->element ); SDL_assert( ret == DISPMANX_SUCCESS ); ret = vc_dispmanx_update_submit_sync( update ); SDL_assert( ret == DISPMANX_SUCCESS ); curdata->element = DISPMANX_NO_HANDLE; } } return 0; } curdata = (RPI_CursorData *) cursor->driverdata; if (curdata == NULL) { return -1; } if (mouse->focus == NULL) { return -1; } display = SDL_GetDisplayForWindow(mouse->focus); if (display == NULL) { return -1; } data = (SDL_DisplayData*) display->driverdata; if (data == NULL) { return -1; } if (curdata->element == DISPMANX_NO_HANDLE) { vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 ); vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h); update = vc_dispmanx_update_start( 10 ); SDL_assert( update ); curdata->element = vc_dispmanx_element_add( update, data->dispman_display, SDL_RPI_MOUSELAYER, // layer &dst_rect, curdata->resource, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, DISPMANX_NO_HANDLE, // clamp VC_IMAGE_ROT0 ); SDL_assert( curdata->element > DISPMANX_NO_HANDLE); ret = vc_dispmanx_update_submit_sync( update ); SDL_assert( ret == DISPMANX_SUCCESS ); } return 0; }
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; }
void EGLWindow::makeSurface(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h) { // this code does the main window creation EGLBoolean result; static EGL_DISPMANX_WINDOW_T nativeWindow; // our source and destination rect for the screen VC_RECT_T dstRect; VC_RECT_T srcRect; // config you use OpenGL ES2.0 by default static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; // get an EGL display connection m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(m_display == EGL_NO_DISPLAY) { std::cerr<<"error getting display\n"; exit(EXIT_FAILURE); } // initialize the EGL display connection int major,minor; result = eglInitialize(m_display, &major, &minor); std::cout<<"EGL init version "<<major<<"."<<minor<<"\n"; if(result == EGL_FALSE) { std::cerr<<"error initialising display\n"; exit(EXIT_FAILURE); } // get our config from the config class m_config->chooseConfig(m_display); EGLConfig config=m_config->getConfig(); // bind the OpenGL API to the EGL result = eglBindAPI(EGL_OPENGL_ES_API); if(result ==EGL_FALSE) { std::cerr<<"error binding API\n"; exit(EXIT_FAILURE); } // create an EGL rendering context m_context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, context_attributes); if(m_context ==EGL_NO_CONTEXT) { std::cerr<<"couldn't get a valid context\n"; exit(EXIT_FAILURE); } // create an EGL window surface the way this works is we set the dimensions of the srec // and destination rectangles. // if these are the same size there is no scaling, else the window will auto scale dstRect.x = _x; dstRect.y = _y; if(m_upscale == false) { dstRect.width = _w; dstRect.height = _h; } else { dstRect.width = m_maxWidth; dstRect.height = m_maxHeight; } srcRect.x = 0; srcRect.y = 0; srcRect.width = _w << 16; srcRect.height = _h << 16; // whilst this is mostly taken from demos I will try to explain what it does // there are very few documents on this ;-0 // open our display with 0 being the first display, there are also some other versions // of this function where we can pass in a mode however the mode is not documented as // far as I can see m_dispmanDisplay = vc_dispmanx_display_open(0); // now we signal to the video core we are going to start updating the config m_dispmanUpdate = vc_dispmanx_update_start(0); // this is the main setup function where we add an element to the display, this is filled in // to the src / dst rectangles m_dispmanElement = vc_dispmanx_element_add ( m_dispmanUpdate, m_dispmanDisplay, 0, &dstRect, 0,&srcRect, DISPMANX_PROTECTION_NONE, 0 ,0,DISPMANX_NO_ROTATE); // now we have created this element we pass it to the native window structure ready // no create our new EGL surface nativeWindow.element = m_dispmanElement; nativeWindow.width =_w; nativeWindow.height =_h; // we now tell the vc we have finished our update vc_dispmanx_update_submit_sync( m_dispmanUpdate ); // finally we can create a new surface using this config and window m_surface = eglCreateWindowSurface( m_display, config, &nativeWindow, NULL ); assert(m_surface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(m_display, m_surface, m_surface, m_context); assert(EGL_FALSE != result); m_activeSurface=true; }
void pi_setvideo_mode(int width, int height) { uint32_t display_width, display_height; uint32_t display_x = 0, display_y = 0; float display_ratio, game_ratio; VC_RECT_T dst_rect; VC_RECT_T src_rect; surface_width = width; surface_height = height; VideoBuffer = (unsigned short *) calloc(1, width * height * 4); // get an EGL display connection display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(display != EGL_NO_DISPLAY); // initialize the EGL display connection EGLBoolean result = eglInitialize(display, NULL, NULL); assert(EGL_FALSE != result); // get an appropriate EGL frame buffer configuration EGLint num_config; EGLConfig config; 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 }; result = eglChooseConfig(display, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); // create an EGL rendering context static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); assert(context != EGL_NO_CONTEXT); // create an EGL window surface int32_t success = graphics_get_display_size(0, &display_width, &display_height); assert(success >= 0); display_adj_width = display_width - (config_options.option_display_border * 2); display_adj_height = display_height - (config_options.option_display_border * 2); if (config_options.display_smooth_stretch) { //We use the dispmanx scaler to smooth stretch the display //so GLES2 doesn't have to handle the performance intensive postprocessing uint32_t sx, sy; // Work out the position and size on the display display_ratio = (float) display_width / (float) display_height; game_ratio = (float) width / (float) height; display_x = sx = display_adj_width; display_y = sy = display_adj_height; if (config_options.maintain_aspect_ratio || game_ratio < 1) { if (game_ratio > display_ratio) sy = (float) display_adj_width / (float) game_ratio; else sx = (float) display_adj_height * (float) game_ratio; } // Centre bitmap on screen display_x = (display_x - sx) / 2; display_y = (display_y - sy) / 2; vc_dispmanx_rect_set(&dst_rect, display_x + config_options.option_display_border, display_y + config_options.option_display_border, sx, sy); } else vc_dispmanx_rect_set(&dst_rect, config_options.option_display_border, config_options.option_display_border, display_adj_width, display_adj_height); if (config_options.display_smooth_stretch) vc_dispmanx_rect_set(&src_rect, 0, 0, width << 16, height << 16); else vc_dispmanx_rect_set(&src_rect, 0, 0, display_adj_width << 16, display_adj_height << 16); dispman_display = vc_dispmanx_display_open(0); dispman_update = vc_dispmanx_update_start(0); dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 10, &dst_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, DISPMANX_NO_ROTATE); //Black background surface dimensions vc_dispmanx_rect_set(&dst_rect, 0, 0, display_width, display_height); vc_dispmanx_rect_set(&src_rect, 0, 0, 128 << 16, 128 << 16); //Create a blank background for the whole screen, make sure width is divisible by 32! uint32_t crap; resource_bg = vc_dispmanx_resource_create(VC_IMAGE_RGB565, 128, 128, &crap); dispman_element_bg = vc_dispmanx_element_add(dispman_update, dispman_display, 9, &dst_rect, resource_bg, &src_rect, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T) 0); nativewindow.element = dispman_element; if (config_options.display_smooth_stretch) { nativewindow.width = width; nativewindow.height = height; } else { nativewindow.width = display_adj_width; nativewindow.height = display_adj_height; } vc_dispmanx_update_submit_sync(dispman_update); surface = eglCreateWindowSurface(display, config, &nativewindow, NULL); assert(surface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(display, surface, surface, context); assert(EGL_FALSE != result); //Smooth stretch the display size for GLES2 is the size of the bitmap //otherwise let GLES2 upscale (NEAR) to the size of the display if (config_options.display_smooth_stretch) gles2_create(width, height, width, height, 16); else gles2_create(display_adj_width, display_adj_height, width, height, 16); }
static void ogl_init(struct state *state) { int32_t success; EGLBoolean result; 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; 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; // We need call eglMakeCurrent beforehand to workaround a bug on rPi. // https://github.com/raspberrypi/firmware/issues/99 eglMakeCurrent(0, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(state->display != EGL_NO_DISPLAY); result = eglInitialize(state->display, NULL, NULL); assert(result != EGL_FALSE); /* Get an appropriate EGL frame buffer config. */ result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config); assert(result != EGL_FALSE); result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes); assert(state->context != EGL_NO_CONTEXT); success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height); assert(success >= 0); /* Prepare VideoCore specific nativewindow to create a window surface. */ dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = state->screen_width; dst_rect.height = state->screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = state->screen_width << 16; src_rect.height = state->screen_height << 16; dispman_display = vc_dispmanx_display_open(0 /* LCD */); 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_TRANSFORM_T(0) /* transform */); nativewindow.element = dispman_element; nativewindow.width = state->screen_width; nativewindow.height = state->screen_height; vc_dispmanx_update_submit_sync(dispman_update); state->surface = eglCreateWindowSurface(state->display, config, &nativewindow, NULL); assert(state->surface != EGL_NO_SURFACE); result = eglMakeCurrent(state->display, state->surface, state->surface, state->context); assert(result != EGL_FALSE); assert(glGetError() == 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 dispmanx_set_texture_frame(void *data, const void *frame, bool rgb32, unsigned width, unsigned height, float alpha) { struct dispmanx_video *_dispvars = data; if (!_dispvars) return; /* If we're entering the menu in this frame, * we must setup rects, resources and menu element. */ if (width != _dispvars->menu_width || height != _dispvars->menu_height) { int i, dst_width, dst_ypos; VC_DISPMANX_ALPHA_T layerAlpha; /* Sanity check */ if (width == 0 || height == 0) return; _dispvars->menu_width = width; _dispvars->menu_height = height; _dispvars->menu_pitch = width * (rgb32 ? 4 : 2); _dispvars->menu_pixFormat = VC_IMAGE_RGBA16; _dispvars->menu_flip_page = 0; /* Transparency disabled */ layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; #if 0 layerAlpha.opacity = (unsigned char)(255.0f * alpha); #endif layerAlpha.opacity = 210; layerAlpha.mask = 0; _dispvars->menu_alpha = &layerAlpha; 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->menu_dstRect), dst_ypos, 0, dst_width, _dispvars->amode.height); /* We configure the rects now. */ vc_dispmanx_rect_set(&(_dispvars->menu_bmpRect), 0, 0, _dispvars->menu_width, _dispvars->menu_height); vc_dispmanx_rect_set(&(_dispvars->menu_srcRect), 0, 0, _dispvars->menu_width << 16, _dispvars->menu_height << 16); /* We create two resources for the menu element. */ _dispvars->menu_resources[0] = vc_dispmanx_resource_create(_dispvars->menu_pixFormat, _dispvars->menu_width, _dispvars->menu_height, &(_dispvars->vcImagePtr)); _dispvars->menu_resources[1] = vc_dispmanx_resource_create(_dispvars->menu_pixFormat, _dispvars->menu_width, _dispvars->menu_height, &(_dispvars->vcImagePtr)); /* Add the menu element. */ _dispvars->update = vc_dispmanx_update_start(0); _dispvars->menu_element = vc_dispmanx_element_add(_dispvars->update, _dispvars->display, 0, &(_dispvars->menu_dstRect), _dispvars->menu_resources[0], &(_dispvars->menu_srcRect), DISPMANX_PROTECTION_NONE, _dispvars->menu_alpha, 0, (DISPMANX_TRANSFORM_T)0); vc_dispmanx_update_submit_sync(_dispvars->update); } /* Flipping is done in every frame, * in the gfx_frame function. * That's why why change flip page here instead. */ _dispvars->menu_flip_page = !_dispvars->menu_flip_page; /* Frame blitting. */ vc_dispmanx_resource_write_data(_dispvars->menu_resources[_dispvars->menu_flip_page], _dispvars->menu_pixFormat, _dispvars->menu_pitch, (void *)frame, &(_dispvars->menu_bmpRect)); /* We don't flip the menu buffers here: * that's done in the gfx_frame function when menu is active. */ }
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 bool pi_create_display(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_RASPBERRYPI *d = (void *)display; ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = _al_get_new_display_settings(); egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (egl_display == EGL_NO_DISPLAY) { return false; } int major, minor; if (!eglInitialize(egl_display, &major, &minor)) { return false; } static EGLint attrib_list[] = { EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; attrib_list[1] = eds->settings[ALLEGRO_DEPTH_SIZE]; attrib_list[3] = eds->settings[ALLEGRO_STENCIL_SIZE]; if (eds->settings[ALLEGRO_RED_SIZE] || eds->settings[ALLEGRO_GREEN_SIZE] || eds->settings[ALLEGRO_BLUE_SIZE] || eds->settings[ALLEGRO_ALPHA_SIZE]) { attrib_list[5] = eds->settings[ALLEGRO_RED_SIZE]; attrib_list[7] = eds->settings[ALLEGRO_GREEN_SIZE]; attrib_list[9] = eds->settings[ALLEGRO_BLUE_SIZE]; attrib_list[11] = eds->settings[ALLEGRO_ALPHA_SIZE]; } else if (eds->settings[ALLEGRO_COLOR_SIZE] == 16) { attrib_list[5] = 5; attrib_list[7] = 6; attrib_list[9] = 5; attrib_list[11] = 0; } EGLConfig config; int num_configs; if (!eglChooseConfig(egl_display, attrib_list, &config, 1, &num_configs)) { return false; } eglBindAPI(EGL_OPENGL_ES_API); int es_ver = (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) ? 2 : 1; static EGLint ctxattr[3] = { EGL_CONTEXT_CLIENT_VERSION, 0xDEADBEEF, EGL_NONE }; ctxattr[1] = es_ver; egl_context = eglCreateContext(egl_display, config, EGL_NO_CONTEXT, ctxattr); if (egl_context == EGL_NO_CONTEXT) { return false; } static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; int dx, dy, screen_width, screen_height; _al_raspberrypi_get_screen_info(&dx, &dy, &screen_width, &screen_height); d->cursor_offset_x = dx; d->cursor_offset_y = dy; dst_rect.x = dx; dst_rect.y = dy; dst_rect.width = screen_width; dst_rect.height = screen_height; d->screen_width = screen_width; d->screen_height = screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = display->w << 16; src_rect.height = display->h << 16; dispman_display = vc_dispmanx_display_open(0 /* LCD */); 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/*transform*/ ); nativewindow.element = dispman_element; nativewindow.width = display->w; nativewindow.height = display->h; vc_dispmanx_update_submit_sync(dispman_update); egl_window = eglCreateWindowSurface( egl_display, config, &nativewindow, NULL); if (egl_window == EGL_NO_SURFACE) { return false; } if (!eglMakeCurrent(egl_display, egl_window, egl_window, egl_context)) { return false; } return true; }
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; }
// Description: Sets the display, OpenGL|ES context and screen stuff void init_ogl(gl_t *state, void *launcher_state) { bcm_host_init(); // Initialize struct memset(state, 0, sizeof(gl_t)); state->controller_1_fd = -1; state->controller_2_fd = -1; state->window_should_close = false; // Set a user pointer up state->user_pointer = launcher_state; int32_t success = 0; EGLBoolean result; 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; 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 }; EGLConfig config; // get an EGL display connection state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(state->display!=EGL_NO_DISPLAY); // initialize the EGL display connection result = eglInitialize(state->display, NULL, NULL); assert(EGL_FALSE != result); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); // get an appropriate EGL frame buffer configuration result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); // create an EGL rendering context state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes); assert(state->context!=EGL_NO_CONTEXT); // create an EGL window surface success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height); assert( success >= 0 ); dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = state->screen_width; dst_rect.height = state->screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = state->screen_width << 16; src_rect.height = state->screen_height << 16; dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 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*/, 0/*transform*/); nativewindow.element = dispman_element; nativewindow.width = state->screen_width; nativewindow.height = state->screen_height; vc_dispmanx_update_submit_sync( dispman_update ); state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL ); assert(state->surface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(state->display, state->surface, state->surface, state->context); assert(EGL_FALSE != result); // Open input event state->controller_1_fd = open("/dev/input/event1",O_RDONLY|O_NONBLOCK); state->controller_2_fd = open("/dev/input/event2",O_RDONLY|O_NONBLOCK); }
void init_ogl(CUBE_STATE_T *state) { int32_t success = 0; EGLBoolean result; EGLint num_config; // bcm_host_init(); static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; 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 }; EGLConfig config; // get an EGL display connection state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); // initialize the EGL display connection result = eglInitialize(state->display, NULL, NULL); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); // get an appropriate EGL frame buffer configuration result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); // create an EGL rendering context state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes); assert(state->context!=EGL_NO_CONTEXT); // create an EGL window surface success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height); assert( success >= 0 ); state->screen_width = 1024; state->screen_height = 1024; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = state->screen_width; dst_rect.height = state->screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = state->screen_width << 16; src_rect.height = state->screen_height << 16; dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 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*/, 0/*transform*/); nativewindow.element = dispman_element; nativewindow.width = state->screen_width; nativewindow.height = state->screen_height; vc_dispmanx_update_submit_sync( dispman_update ); state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL ); assert(state->surface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(state->display, state->surface, state->surface, state->context); assert(EGL_FALSE != result); }
/** @brief Obtain a reference to the system's native window * @param width : desired pixel width of the window (not used by all platforms) * @param height : desired pixel height of the window (not used by all platforms) * @return : 0 if the function passed, else 1 */ int8_t GetNativeWindow( uint16_t width, uint16_t height ) { nativeWindow = 0; #if defined(WIZ) || defined(CAANOO) nativeWindow = (NativeWindowType)malloc(16*1024); if(nativeWindow == NULL) { printf( "EGLport ERROR: Memory for window Failed\n" ); return 1; } #elif defined(RPI) EGLBoolean result; uint32_t screen_width, screen_height; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; /* create an EGL window surface */ result = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height); if(result < 0) { printf( "EGLport ERROR: RPi graphicget_display_size failed\n" ); return 1; } dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = screen_width; dst_rect.height = screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = width << 16; src_rect.height = height << 16; dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 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, (VC_DISPMANX_ALPHA_T*)0 /*alpha*/, (DISPMANX_CLAMP_T*)0 /*clamp*/, (DISPMANX_TRANSFORM_T)0 /*transform*/); nativewindow.element = dispman_element; nativewindow.width = screen_width; nativewindow.height = screen_height; vc_dispmanx_update_submit_sync( dispman_update ); nativeWindow = (NativeWindowType)&nativewindow; #else /* default */ if (eglSettings[CFG_MODE] == RENDER_RAW) /* RAW FB mode */ { nativeWindow = 0; } else if(eglSettings[CFG_MODE] == RENDER_SDL) /* SDL/X11 mode */ { #if defined(USE_EGL_SDL) /* SDL_GetWMInfo is populated when display was opened */ nativeWindow = (NativeWindowType)sysWmInfo.info.x11.window; if (nativeWindow == 0) { printf( "EGLport ERROR: unable to get window!\n" ); return 1; } #else printf( "EGLport ERROR: SDL mode was not enabled in this compile!\n" ); #endif } else { printf( "EGLport ERROR: Unknown EGL render mode %d!\n", eglSettings[CFG_MODE] ); return 1; } #endif /* WIZ / CAANOO */ return 0; }
bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) { #ifdef BUILD_RASPI bcm_host_init(); renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); int major, minor; if (EGL_FALSE == eglInitialize(renderer->display, &major, &minor)) { printf("Failed to initialize EGL"); return false; } if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) { printf("Failed to get GLES API"); return false; } const EGLint requestConfig[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 5, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, 1, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EGLConfig config; EGLint numConfigs; if (EGL_FALSE == eglChooseConfig(renderer->display, requestConfig, &config, 1, &numConfigs)) { printf("Failed to choose EGL config\n"); return false; } const EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; int dispWidth = 240, dispHeight = 160, adjWidth; renderer->context = eglCreateContext(renderer->display, config, EGL_NO_CONTEXT, contextAttributes); graphics_get_display_size(0, &dispWidth, &dispHeight); adjWidth = dispHeight / 2 * 3; DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0); DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); VC_RECT_T destRect = { .x = (dispWidth - adjWidth) / 2, .y = 0, .width = adjWidth, .height = dispHeight }; VC_RECT_T srcRect = { .x = 0, .y = 0, .width = 240 << 16, .height = 160 << 16 }; DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, 0); vc_dispmanx_update_submit_sync(update); renderer->window.element = element; renderer->window.width = dispWidth; renderer->window.height = dispHeight; renderer->surface = eglCreateWindowSurface(renderer->display, config, &renderer->window, 0); if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) { return false; } #else GBASDLGLCommonInit(renderer); #endif renderer->d.outputBuffer = memalign(16, 256 * 256 * 4); renderer->d.outputBufferStride = 256; GBAGLES2ContextCreate(&renderer->gl2); renderer->gl2.d.user = renderer; renderer->gl2.d.lockAspectRatio = renderer->lockAspectRatio; renderer->gl2.d.filter = renderer->filter; renderer->gl2.d.swap = GBASDLGLCommonSwap; renderer->gl2.d.init(&renderer->gl2.d, 0); return true; } void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { SDL_Event event; struct VideoBackend* v = &renderer->gl2.d; while (context->state < THREAD_EXITING) { while (SDL_PollEvent(&event)) { GBASDLHandleEvent(context, &renderer->player, &event); } if (GBASyncWaitFrameStart(&context->sync)) { v->postFrame(v, renderer->d.outputBuffer); } GBASyncWaitFrameEnd(&context->sync); v->drawFrame(v); #ifdef BUILD_RASPI eglSwapBuffers(renderer->display, renderer->surface); #else v->swap(v); #endif } } void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer) { if (renderer->gl2.d.deinit) { renderer->gl2.d.deinit(&renderer->gl2.d); } #ifdef BUILD_RASPI eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(renderer->display, renderer->surface); eglDestroyContext(renderer->display, renderer->context); eglTerminate(renderer->display); bcm_host_deinit(); #elif SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_DeleteContext(renderer->glCtx); #endif free(renderer->d.outputBuffer); }
bool createSurface() //unsigned int display_width, unsigned int display_height) { LOG(LogInfo) << "Starting SDL..."; if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) != 0) { LOG(LogError) << "Error initializing SDL!\n " << SDL_GetError() << "\n" << "Are you in the 'video', 'audio', and 'input' groups? Is X closed? Is your firmware up to date? Are you using at least the 192/64 memory split?"; return false; } sdlScreen = SDL_SetVideoMode(1, 1, 0, SDL_SWSURFACE); if(sdlScreen == NULL) { LOG(LogError) << "Error creating SDL window for input!"; return false; } LOG(LogInfo) << "Creating surface..."; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(display == EGL_NO_DISPLAY) { LOG(LogError) << "Error getting display!"; return false; } bool result = eglInitialize(display, NULL, NULL); if(result == EGL_FALSE) { LOG(LogError) << "Error initializing display!"; return false; } result = eglBindAPI(EGL_OPENGL_ES_API); if(result == EGL_FALSE) { LOG(LogError) << "Error binding API!"; return false; } static const EGLint config_attributes[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; GLint numConfigs; result = eglChooseConfig(display, config_attributes, &config, 1, &numConfigs); if(result == EGL_FALSE) { LOG(LogError) << "Error choosing config!"; return false; } context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL); if(context == EGL_NO_CONTEXT) { LOG(LogError) << "Error getting context!\n " << eglGetError(); return false; } if(!display_width || !display_height) { bool success = graphics_get_display_size(0, &display_width, &display_height); //0 = LCD if(success < 0) { LOG(LogError) << "Error getting display size!"; return false; } } LOG(LogInfo) << "Resolution: " << display_width << "x" << display_height << "..."; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = display_width; dst_rect.height = display_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = display_width << 16; src_rect.height = display_height << 16; dispman_display = vc_dispmanx_display_open(0); //0 = LCD 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 /*transform*/); nativewindow.element = dispman_element; nativewindow.width = display_width; nativewindow.height = display_height; vc_dispmanx_update_submit_sync(dispman_update); surface = eglCreateWindowSurface(display, config, &nativewindow, NULL); if(surface == EGL_NO_SURFACE) { LOG(LogError) << "Error creating window surface!"; return false; } result = eglMakeCurrent(display, surface, surface, context); if(result == EGL_FALSE) { LOG(LogError) << "Error with eglMakeCurrent!"; return false; } LOG(LogInfo) << "Created surface successfully!"; return true; }
ViewBackend::Cursor::~Cursor() { DISPMANX_UPDATE_HANDLE_T updateHandle = vc_dispmanx_update_start(0); vc_dispmanx_element_remove(updateHandle, cursorHandle); vc_dispmanx_update_submit_sync(updateHandle); }
/*********************************************************** * Name: init_ogl * * Arguments: * CUBE_STATE_T *state - holds OGLES model info * * Description: Sets the display, OpenGL|ES context and screen stuff * * Returns: void * ***********************************************************/ static void init_ogl(CUBE_STATE_T *state) { int32_t success = 0; EGLBoolean result; 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; 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_DEPTH_SIZE, 16, //EGL_SAMPLES, 4, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EGLConfig config; // get an EGL display connection state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(state->display!=EGL_NO_DISPLAY); // initialize the EGL display connection result = eglInitialize(state->display, NULL, NULL); assert(EGL_FALSE != result); // get an appropriate EGL frame buffer configuration // this uses a BRCM extension that gets the closest match, rather than standard which returns anything that matches result = eglSaneChooseConfigBRCM(state->display, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); // create an EGL rendering context state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL); assert(state->context!=EGL_NO_CONTEXT); // create an EGL window surface success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height); assert( success >= 0 ); dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = state->screen_width; dst_rect.height = state->screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = state->screen_width << 16; src_rect.height = state->screen_height << 16; dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 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*/, 0/*transform*/); nativewindow.element = dispman_element; nativewindow.width = state->screen_width; nativewindow.height = state->screen_height; vc_dispmanx_update_submit_sync( dispman_update ); state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL ); assert(state->surface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(state->display, state->surface, state->surface, state->context); assert(EGL_FALSE != result); // Set background color and clear buffers glClearColor(0.15f, 0.25f, 0.35f, 1.0f); // Enable back face culling. glEnable(GL_CULL_FACE); glMatrixMode(GL_MODELVIEW); }
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; }
int rpi_setup_element(int x, int y, Uint32 video_flags, int update) { // this code is based on the work of Ben O'Steen // http://benosteen.wordpress.com/2012/04/27/using-opengl-es-2-0-on-the-raspberry-pi-without-x-windows/ // https://github.com/benosteen/opengles-book-samples/tree/master/Raspi DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; VC_DISPMANX_ALPHA_T alpha_descriptor; uint32_t rpi_display_device=DISPMANX_ID_MAIN_LCD; uint32_t display_width; uint32_t display_height; int success; success = graphics_get_display_size(rpi_display_device, &display_width, &display_height); if ( success < 0 ) { con_printf(CON_URGENT, "Could not get RPi display size, assuming 640x480\n"); display_width=640; display_height=480; } if ((uint32_t)x > display_width) { con_printf(CON_URGENT, "RPi: Requested width %d exceeds display width %u, scaling down!\n", x,display_width); x=(int)display_width; } if ((uint32_t)y > display_height) { con_printf(CON_URGENT, "RPi: Requested height %d exceeds display height %u, scaling down!\n", y,display_height); y=(int)display_height; } con_printf(CON_DEBUG, "RPi: display resolution %ux%u, game resolution: %dx%d (%s)\n", display_width, display_height, x, y, (video_flags & SDL_FULLSCREEN)?"fullscreen":"windowed"); if (video_flags & SDL_FULLSCREEN) { /* scale to the full display size... */ dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = display_width; dst_rect.height= display_height; } else { /* TODO: we could query the position of the X11 window here and try to place the ovelray exactly above that..., we would have to track window movements, though ... */ dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = (uint32_t)x; dst_rect.height= (uint32_t)y; } src_rect.x = 0; src_rect.y = 0; src_rect.width = ((uint32_t)x)<< 16; src_rect.height =((uint32_t)y)<< 16; /* we do not want our overlay to be blended against the background */ alpha_descriptor.flags=DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; alpha_descriptor.opacity=0xffffffff; alpha_descriptor.mask=0; // open display, if we do not already have one ... if (dispman_display == DISPMANX_NO_HANDLE) { con_printf(CON_DEBUG, "RPi: opening display: %u\n",rpi_display_device); dispman_display = vc_dispmanx_display_open(rpi_display_device); if (dispman_display == DISPMANX_NO_HANDLE) { con_printf(CON_URGENT,"RPi: failed to open display: %u\n",rpi_display_device); } } if (dispman_element != DISPMANX_NO_HANDLE) { if (!update) { // if the element already exists, and we cannot update it, so recreate it rpi_destroy_element(); } } else { // if the element does not exist, we cannot do an update update=0; } dispman_update = vc_dispmanx_update_start( 0 ); if (update) { con_printf(CON_DEBUG, "RPi: updating display manager element\n"); vc_dispmanx_element_change_attributes ( dispman_update, nativewindow.element, ELEMENT_CHANGE_DEST_RECT | ELEMENT_CHANGE_SRC_RECT, 0 /*layer*/, 0 /*opacity*/, &dst_rect, &src_rect, 0 /*mask*/, VC_IMAGE_ROT0 /*transform*/); } else { // create a new element con_printf(CON_DEBUG, "RPi: creating display manager element\n"); dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha_descriptor, NULL /*clamp*/, VC_IMAGE_ROT0 /*transform*/); if (dispman_element == DISPMANX_NO_HANDLE) { con_printf(CON_URGENT,"RPi: failed to creat display manager elemenr\n"); } nativewindow.element = dispman_element; } nativewindow.width = display_width; nativewindow.height = display_height; vc_dispmanx_update_submit_sync( dispman_update ); return 0; }
static int rpi_init(struct MPGLContext *ctx, int flags) { struct priv *p = ctx->priv; struct vo *vo = ctx->vo; p->egl.log = vo->log; bcm_host_init(); p->display = vc_dispmanx_display_open(0); p->update = vc_dispmanx_update_start(0); if (!p->display || !p->update) { MP_FATAL(ctx->vo, "Could not get DISPMANX objects.\n"); goto fail; } uint32_t w, h; if (graphics_get_display_size(0, &w, &h) < 0) { MP_FATAL(ctx->vo, "Could not get display size.\n"); goto fail; } // dispmanx is like a neanderthal version of Wayland - you can add an // overlay any place on the screen. Just use the whole screen. VC_RECT_T dst = {.width = w, .height = h}; VC_RECT_T src = {.width = w << 16, .height = h << 16}; VC_DISPMANX_ALPHA_T alpha = { .flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, .opacity = 0xFF, }; p->window = vc_dispmanx_element_add(p->update, p->display, 1, &dst, 0, &src, DISPMANX_PROTECTION_NONE, &alpha, 0, 0); if (!p->window) { MP_FATAL(ctx->vo, "Could not add DISPMANX element.\n"); goto fail; } vc_dispmanx_update_submit_sync(p->update); if (mp_egl_rpi_init(&p->egl, p->window, w, h) < 0) goto fail; ctx->gl = p->egl.gl; vo->dwidth = p->w = w; vo->dheight = p->h = h; return 0; fail: rpi_uninit(ctx); return -1; } static int rpi_reconfig(struct MPGLContext *ctx) { struct priv *p = ctx->priv; ctx->vo->dwidth = p->w; ctx->vo->dheight = p->h; return 0; } static void rpi_swap_buffers(MPGLContext *ctx) { struct priv *p = ctx->priv; eglSwapBuffers(p->egl.egl_display, p->egl.egl_surface); } static int rpi_control(MPGLContext *ctx, int *events, int request, void *arg) { return VO_NOTIMPL; } const struct mpgl_driver mpgl_driver_rpi = { .name = "rpi", .priv_size = sizeof(struct priv), .init = rpi_init, .reconfig = rpi_reconfig, .swap_buffers = rpi_swap_buffers, .control = rpi_control, .uninit = rpi_uninit, };
//============================================================================== void initGL(int argc, char **argv){ // Start OpenGL ES bcm_host_init(); // Clear application state int32_t success = 0; EGLBoolean result; EGLint num_config; static EGL_DISPMANX_WINDOW_T nativeviewport; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; uint32_t screen_width; uint32_t screen_height; 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_DEPTH_SIZE, 16, EGL_NONE }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLConfig config; // get an EGL display connection display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(display!=EGL_NO_DISPLAY); check(); // initialize the EGL display connection result = eglInitialize(display, NULL, NULL); assert(EGL_FALSE != result); check(); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(display, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); check(); // get an appropriate EGL frame buffer configuration result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); check(); // create an EGL rendering context context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); assert(context!=EGL_NO_CONTEXT); check(); // create an EGL viewport surface success = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height); assert( success >= 0 ); // Initially the viewport is for all the screen viewport.x = 0; viewport.y = 0; viewport.z = screen_width; viewport.w = screen_height; dst_rect.x = viewport.x; dst_rect.y = viewport.y; dst_rect.width = viewport.z; dst_rect.height = viewport.w; src_rect.x = 0; src_rect.y = 0; src_rect.width = viewport.z << 16; src_rect.height = viewport.w << 16; dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 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_TRANSFORM_T)0/*transform*/); nativeviewport.element = dispman_element; nativeviewport.width = viewport.z; nativeviewport.height = viewport.w; vc_dispmanx_update_submit_sync( dispman_update ); check(); surface = eglCreateWindowSurface( display, config, &nativeviewport, NULL ); assert(surface != EGL_NO_SURFACE); check(); // connect the context to the surface result = eglMakeCurrent(display, surface, surface, context); assert(EGL_FALSE != result); check(); // Set background color and clear buffers // glClearColor(0.15f, 0.25f, 0.35f, 1.0f); // glClear( GL_COLOR_BUFFER_BIT ); setWindowSize(viewport.z,viewport.w); mouse.x = viewport.z*0.5; mouse.y = viewport.w*0.5; check(); initMouse(); ///printf("OpenGL Initialize at %i,%i,%i,%i\n",viewport.x,viewport.y,viewport.z,viewport.w); }
ogEGLWindow::ogEGLWindow( uint32_t a_width, uint32_t a_height, ogEGLConfigShPtr a_config_shptr ) { this->m_width = a_width; this->m_height = a_height; // get max display size int32_t result = 0; result = graphics_get_display_size( 0, &(this->m_max_width), &(this->m_max_height) ); //!!! std::cout << "ogEGLWindowShPtr::ogEGLWindow : graphics get display size result = " << result << ", max width : " << this->m_max_width << std::endl; assert( result >= 0 ); if ( this->m_max_width < a_width ) { this->m_width = this->m_max_width; } if ( this->m_max_height < a_height ) { this->m_height = this->m_max_height; } this->m_config_shptr = a_config_shptr; std::cout << "ogEGLWindow::ogEGLWindow | Display max width : " << this->m_max_width << ", max height : " << this->m_max_height << std::endl; // make surface EGLBoolean success; static EGL_DISPMANX_WINDOW_T native_window; VC_RECT_T src_rect; VC_RECT_T dst_rect; static const EGLint ar_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; this->m_display = eglGetDisplay( EGL_DEFAULT_DISPLAY ); if ( this->m_display == EGL_NO_DISPLAY ) { std::cerr << "ogEGLWindow::ogEGLWindow | eglGetDisplay returned EGL_NO_DISPLAY" << std::endl; exit( EXIT_FAILURE ); } int major, minor; success = eglInitialize( this->m_display, &major, &minor ); if ( success = EGL_FALSE ) { std::cerr << "ogEGLWindow::ogEGLWindow | eglInitialize returned EGL_FALSE" << std::endl; exit( EXIT_FAILURE ); } this->m_config_shptr->chooseConfig( this->m_display ); success = eglBindAPI( EGL_OPENGL_ES_API ); if ( success = EGL_FALSE ) { std::cerr << "ogEGLWindow::ogEGLWindow | eglBindAPI returned EGL_FALSE" << std::endl; exit( EXIT_FAILURE ); } this->m_context = eglCreateContext( this->m_display, this->m_config_shptr->getConfig(), EGL_NO_CONTEXT, ar_context_attributes ); if ( success = EGL_FALSE ) { std::cerr << "ogEGLWindow::ogEGLWindow | eglCreateContext returned EGL_FALSE" << std::endl; exit( EXIT_FAILURE ); } src_rect.x = 0; src_rect.y = 0; src_rect.width = this->m_width << 16; src_rect.height = this->m_height << 16; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = this->m_width; dst_rect.height = this->m_height; this->m_dispmanx_display = vc_dispmanx_display_open( 0 ); this->m_dispmanx_update = vc_dispmanx_update_start( 0 ); this->m_dispmanx_element = vc_dispmanx_element_add( this->m_dispmanx_update, this->m_dispmanx_display, 0, &dst_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, 0, 0, DISPMANX_NO_ROTATE ); native_window.element = this->m_dispmanx_element; native_window.width = this->m_width; native_window.height = this->m_height; vc_dispmanx_update_submit_sync( this->m_dispmanx_update ); this->m_surface = eglCreateWindowSurface( this->m_display, this->m_config_shptr->getConfig(), &native_window, NULL ); assert( this->m_surface != EGL_NO_SURFACE ); success = eglMakeCurrent( this->m_display, this->m_surface, this->m_surface, this->m_context ); } // ogEGLWindow::ogEGLWindow
void InitGraphics() { bcm_host_init(); int32_t success = 0; EGLBoolean result; 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; 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 }; EGLConfig config; // get an EGL display connection GDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(GDisplay!=EGL_NO_DISPLAY); check(); // initialize the EGL display connection result = eglInitialize(GDisplay, NULL, NULL); assert(EGL_FALSE != result); check(); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(GDisplay, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); check(); // get an appropriate EGL frame buffer configuration result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); check(); // create an EGL rendering context GContext = eglCreateContext(GDisplay, config, EGL_NO_CONTEXT, context_attributes); assert(GContext!=EGL_NO_CONTEXT); check(); // create an EGL window surface success = graphics_get_display_size(0 /* LCD */, &GScreenWidth, &GScreenHeight); assert( success >= 0 ); dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = GScreenWidth; dst_rect.height = GScreenHeight; src_rect.x = 0; src_rect.y = 0; src_rect.width = GScreenWidth << 16; src_rect.height = GScreenHeight << 16; dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 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_TRANSFORM_T)0/*transform*/); nativewindow.element = dispman_element; nativewindow.width = GScreenWidth; nativewindow.height = GScreenHeight; vc_dispmanx_update_submit_sync( dispman_update ); check(); GSurface = eglCreateWindowSurface( GDisplay, config, &nativewindow, NULL ); assert(GSurface != EGL_NO_SURFACE); check(); // connect the context to the surface result = eglMakeCurrent(GDisplay, GSurface, GSurface, GContext); assert(EGL_FALSE != result); check(); // Set background color and clear buffers glClearColor(0.15f, 0.25f, 0.35f, 1.0f); glClear( GL_COLOR_BUFFER_BIT ); //load the test shaders GSimpleVS.LoadVertexShader("simplevertshader.glsl"); GSimpleFS.LoadFragmentShader("simplefragshader.glsl"); GSimpleProg.Create(&GSimpleVS,&GSimpleFS); check(); glUseProgram(GSimpleProg.GetId()); check(); //create an ickle vertex buffer static const GLfloat quad_vertex_positions[] = { 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; glGenBuffers(1, &GQuadVertexBuffer); check(); glBindBuffer(GL_ARRAY_BUFFER, GQuadVertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertex_positions), quad_vertex_positions, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); check(); }
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); }
bool Window::initialize() { bcm_host_init(); m_pSDLWindow = SDL_CreateWindow("SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, 0); if (NULL == m_pSDLWindow) { return false; } m_pDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (EGL_NO_DISPLAY == m_pDisplay) { Log::instance()->logError("Unable to get display %d", eglGetError()); return false; } EGLint iMajor; EGLint iMinor; if (EGL_FALSE == eglInitialize(m_pDisplay, &iMajor, &iMinor)) { Log::instance()->logError("Unable to initialize EGL %d", eglGetError()); return false; } EGLint iConfigAttributes[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, 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; int iConfigs; if (EGL_FALSE == eglChooseConfig(m_pDisplay, iConfigAttributes, &config, 1, &iConfigs)) { Log::instance()->logError("Unable to choose config %d", eglGetError()); return false; } m_pContext = eglCreateContext(m_pDisplay, config, EGL_NO_CONTEXT, NULL); if (EGL_NO_CONTEXT == m_pContext) { Log::instance()->logError("Unable to create context %d", eglGetError()); return false; } uint32_t iMaxWidth = 0; uint32_t iMaxHeight = 0; if (graphics_get_display_size(0, &iMaxWidth, &iMaxHeight) < 0) { Log::instance()->logError("Unable to get display size"); return false; } #if SCALED_DISPLAY const GameHeader& gameHeader = System::getGameHeader(); VC_RECT_T src; src.x = 0; src.y = 0; src.width = gameHeader.iScreenWidth << 16; src.height = gameHeader.iScreenHeight << 16; VC_RECT_T dest; dest.x = 0; dest.y = 0; dest.width = iMaxWidth; dest.height = iMaxHeight; DISPMANX_ELEMENT_HANDLE_T element; DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_UPDATE_HANDLE_T update; display = vc_dispmanx_display_open(0); update = vc_dispmanx_update_start(0); element = vc_dispmanx_element_add(update, display, 0, &dest, 0, &src, DISPMANX_PROTECTION_NONE, NULL, NULL, DISPMANX_NO_ROTATE); m_window.element = element; m_window.width = gameHeader.iScreenWidth; m_window.height = gameHeader.iScreenHeight; vc_dispmanx_update_submit_sync(update); m_pSurface = eglCreateWindowSurface(m_pDisplay, config, &m_window, NULL); if (EGL_NO_SURFACE == m_pSurface) { Log::instance()->logError("Unable to create window surface %d", eglGetError()); return false; } if (EGL_FALSE == eglMakeCurrent(m_pDisplay, m_pSurface, m_pSurface, m_pContext)) { Log::instance()->logError("Unable to set current context %d", eglGetError()); return false; } #else VC_RECT_T src; src.x = 0; src.y = 0; src.width = iMaxWidth; src.height = iMaxHeight; VC_RECT_T dest; dest.x = 0; dest.y = 0; dest.width = iMaxWidth; dest.height = iMaxHeight; DISPMANX_ELEMENT_HANDLE_T element; DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_UPDATE_HANDLE_T update; display = vc_dispmanx_display_open(0); update = vc_dispmanx_update_start(0); element = vc_dispmanx_element_add(update, display, 0, &dest, 0, &src, DISPMANX_PROTECTION_NONE, NULL, NULL, DISPMANX_NO_ROTATE); m_window.element = element; m_window.width = iMaxWidth; m_window.height = iMaxHeight; vc_dispmanx_update_submit_sync(update); m_pSurface = eglCreateWindowSurface(m_pDisplay, config, &m_window, NULL); if (EGL_NO_SURFACE == m_pSurface) { Log::instance()->logError("Unable to create window surface %d", eglGetError()); return false; } if (EGL_FALSE == eglMakeCurrent(m_pDisplay, m_pSurface, m_pSurface, m_pContext)) { Log::instance()->logError("Unable to set current context %d", eglGetError()); return false; } const GameHeader& gameHeader = System::getUpdateableGameHeader(); gameHeader.iScreenWidth = iMaxWidth; gameHeader.iScreenHeight = iMaxHeight; #endif // Set swap interval if (EGL_FALSE == eglSwapInterval(m_pDisplay, 1)) { Log::instance()->logError("Unable to set swap interval context"); } return true; }
int piInitVideo() { bcm_host_init(); // get an EGL display connection display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (display == EGL_NO_DISPLAY) { fprintf(stderr, "eglGetDisplay() failed: EGL_NO_DISPLAY\n"); return 0; } // initialize the EGL display connection EGLBoolean result = eglInitialize(display, NULL, NULL); if (result == EGL_FALSE) { fprintf(stderr, "eglInitialize() failed: EGL_FALSE\n"); return 0; } // get an appropriate EGL frame buffer configuration EGLint numConfig; EGLConfig config; static const EGLint attributeList[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; result = eglChooseConfig(display, attributeList, &config, 1, &numConfig); if (result == EGL_FALSE) { fprintf(stderr, "eglChooseConfig() failed: EGL_FALSE\n"); return 0; } result = eglBindAPI(EGL_OPENGL_ES_API); if (result == EGL_FALSE) { fprintf(stderr, "eglBindAPI() failed: EGL_FALSE\n"); return 0; } // create an EGL rendering context static const EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes); if (context == EGL_NO_CONTEXT) { fprintf(stderr, "eglCreateContext() failed: EGL_NO_CONTEXT\n"); return 0; } // create an EGL window surface int32_t success = graphics_get_display_size(0, &screenWidth, &screenHeight); if (result < 0) { fprintf(stderr, "graphics_get_display_size() failed: < 0\n"); return 0; } fprintf(stderr, "Width/height: %d/%d\n", screenWidth, screenHeight); VC_RECT_T dstRect; dstRect.x = 0; dstRect.y = 0; dstRect.width = screenWidth; dstRect.height = screenHeight; VC_RECT_T srcRect; srcRect.x = 0; srcRect.y = 0; srcRect.width = screenWidth << 16; srcRect.height = screenHeight << 16; DISPMANX_DISPLAY_HANDLE_T dispManDisplay = vc_dispmanx_display_open(0); DISPMANX_UPDATE_HANDLE_T dispmanUpdate = vc_dispmanx_update_start(0); DISPMANX_ELEMENT_HANDLE_T dispmanElement = vc_dispmanx_element_add(dispmanUpdate, dispManDisplay, 0, &dstRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, NULL, NULL, DISPMANX_NO_ROTATE); nativeWindow.element = dispmanElement; nativeWindow.width = screenWidth; nativeWindow.height = screenHeight; vc_dispmanx_update_submit_sync(dispmanUpdate); fprintf(stderr, "Initializing window surface...\n"); surface = eglCreateWindowSurface(display, config, &nativeWindow, NULL); if (surface == EGL_NO_SURFACE) { fprintf(stderr, "eglCreateWindowSurface() failed: EGL_NO_SURFACE\n"); return 0; } fprintf(stderr, "Connecting context to surface...\n"); // connect the context to the surface result = eglMakeCurrent(display, surface, surface, context); if (result == EGL_FALSE) { fprintf(stderr, "eglMakeCurrent() failed: EGL_FALSE\n"); return 0; } fprintf(stderr, "Initializing shaders...\n"); // Init shader resources memset(&shader, 0, sizeof(ShaderInfo)); shader.program = createProgram(vertexShaderSrc, fragmentShaderSrc); if (!shader.program) { fprintf(stderr, "createProgram() failed\n"); return 0; } fprintf(stderr, "Initializing textures/buffers...\n"); shader.a_position = glGetAttribLocation(shader.program, "a_position"); shader.a_texcoord = glGetAttribLocation(shader.program, "a_texcoord"); shader.u_vp_matrix = glGetUniformLocation(shader.program, "u_vp_matrix"); shader.u_texture = glGetUniformLocation(shader.program, "u_texture"); glGenTextures(1, textures); glBindTexture(GL_TEXTURE_2D, textures[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_WIDTH, TEX_HEIGHT, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL); glGenBuffers(3, buffers); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 3, vertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 2, uvs, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, kIndexCount * sizeof(GL_UNSIGNED_SHORT), indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); float sx = 1.0f; float sy = 1.0f; float zoom = (float)ZOOM; // Screen aspect ratio adjustment float a = (float)screenWidth / screenHeight; float a0 = (float)WIDTH / (float)HEIGHT; if (a > a0) { sx = a0/a; } else { sy = a/a0; } setOrtho(projection, -0.5f, +0.5f, +0.5f, -0.5f, -1.0f, 1.0f, sx * zoom, sy * zoom); fprintf(stderr, "Setting up screen...\n"); msxScreenPitch = WIDTH * BIT_DEPTH / 8; msxScreen = (char*)calloc(1, BIT_DEPTH / 8 * TEX_WIDTH * TEX_HEIGHT); if (!msxScreen) { fprintf(stderr, "Error allocating screen texture\n"); return 0; } fprintf(stderr, "Initializing SDL video...\n"); // We're doing our own video rendering - this is just so SDL-based keyboard // can work sdlScreen = SDL_SetVideoMode(0, 0, 0, 0); return 1; }
/*********************************************************** * Name: init_egl * * Arguments: * CUBE_STATE_T *state - holds OGLES model info * * Description: Sets the display, OpenGL|ES context and screen stuff * * Returns: void * ***********************************************************/ static void init_egl(void) { int32_t success = 0; EGLBoolean result; 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; 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_DEPTH_SIZE, 16, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; static EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; EGLConfig config; // get an EGL display connection state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(state->display!=EGL_NO_DISPLAY); // initialize the EGL display connection result = eglInitialize(state->display, NULL, NULL); assert(EGL_FALSE != result); // get an appropriate EGL frame buffer configuration result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config); assert(EGL_FALSE != result); // bind the gles api to this thread - this is default so not required result = eglBindAPI(EGL_OPENGL_ES_API); assert(EGL_FALSE != result); // create an EGL rendering context // select es 1.x or 2.x based on user option context_attributes[1] = state->useGLES2 + 1; state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes); assert(state->context!=EGL_NO_CONTEXT); // create an EGL window surface success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height); assert( success >= 0 ); dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = state->screen_width; dst_rect.height = state->screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = state->screen_width << 16; src_rect.height = state->screen_height << 16; dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 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*/, 0/*transform*/); nativewindow.element = dispman_element; nativewindow.width = state->screen_width; nativewindow.height = state->screen_height; vc_dispmanx_update_submit_sync( dispman_update ); state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL ); assert(state->surface != EGL_NO_SURFACE); // connect the context to the surface result = eglMakeCurrent(state->display, state->surface, state->surface, state->context); assert(EGL_FALSE != result); // default to no vertical sync but user option may turn it on result = eglSwapInterval(state->display, state->useVSync ); assert(EGL_FALSE != result); // Set background color and clear buffers glClearColor(0.25f, 0.45f, 0.55f, 1.0f); // Enable back face culling. glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); if (state->wantInfo) { printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); } }