static void gl_free(void *data) { #ifdef RARCH_CONSOLE if (driver.video_data) return; #endif gl_t *gl = (gl_t*)data; gl_deinit_font(gl); gl_shader_deinit(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDeleteTextures(TEXTURES, gl->texture); #ifdef HAVE_OPENGL_TEXREF glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); glDeleteBuffers(1, &gl->pbo); #endif #ifdef HAVE_FBO gl_deinit_fbo(gl); #endif gfx_ctx_destroy(); if (gl->empty_buf) free(gl->empty_buf); free(gl); }
static bool gfx_ctx_init(void) { if (g_inited) return false; static const int visual_attribs[] = { GLX_X_RENDERABLE , True, GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, GLX_RENDER_TYPE , GLX_RGBA_BIT, GLX_DOUBLEBUFFER , True, GLX_RED_SIZE , 8, GLX_GREEN_SIZE , 8, GLX_BLUE_SIZE , 8, GLX_ALPHA_SIZE , 8, GLX_DEPTH_SIZE , 0, GLX_STENCIL_SIZE , 0, None }; GLXFBConfig *fbcs = NULL; g_quit = 0; init_lut(); g_dpy = XOpenDisplay(NULL); if (!g_dpy) goto error; // GLX 1.3+ required. int major, minor; glXQueryVersion(g_dpy, &major, &minor); if (major < 1 || (major == 1 && minor < 3)) goto error; int nelements; fbcs = glXChooseFBConfig(g_dpy, DefaultScreen(g_dpy), visual_attribs, &nelements); if (!fbcs) goto error; if (!nelements) { XFree(fbcs); goto error; } g_fbc = fbcs[0]; XFree(fbcs); return true; error: gfx_ctx_destroy(); return false; }
static bool gfx_ctx_set_video_mode( unsigned width, unsigned height, bool fullscreen) { if (g_inited) return false; int ret = 0; struct drm_fb *fb = NULL; struct sigaction sa = {{0}}; sa.sa_handler = sighandler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); #define EGL_ATTRIBS_BASE \ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \ EGL_RED_SIZE, 1, \ EGL_GREEN_SIZE, 1, \ EGL_BLUE_SIZE, 1, \ EGL_ALPHA_SIZE, 0, \ EGL_DEPTH_SIZE, 0 static const EGLint egl_attribs_gl[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE, }; static const EGLint egl_attribs_gles[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE, }; static const EGLint egl_attribs_vg[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, EGL_NONE, }; // GLES 2.0. Don't use for any other API. static const EGLint gles_context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; const EGLint *attrib_ptr; switch (g_api) { case GFX_CTX_OPENGL_API: attrib_ptr = egl_attribs_gl; break; case GFX_CTX_OPENGL_ES_API: attrib_ptr = egl_attribs_gles; break; case GFX_CTX_OPENVG_API: attrib_ptr = egl_attribs_vg; break; default: attrib_ptr = NULL; } g_egl_dpy = eglGetDisplay((EGLNativeDisplayType)g_gbm_dev); if (!g_egl_dpy) { RARCH_ERR("[KMS/EGL]: Couldn't get EGL display.\n"); goto error; } EGLint major, minor; if (!eglInitialize(g_egl_dpy, &major, &minor)) goto error; EGLint n; if (!eglChooseConfig(g_egl_dpy, attrib_ptr, &g_config, 1, &n) || n != 1) goto error; g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, (g_api == GFX_CTX_OPENGL_ES_API) ? gles_context_attribs : NULL); if (!g_egl_ctx) goto error; g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, (EGLNativeWindowType)g_gbm_surface, NULL); if (!g_egl_surf) goto error; if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) goto error; glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(g_egl_dpy, g_egl_surf); g_bo = gbm_surface_lock_front_buffer(g_gbm_surface); fb = drm_fb_get_from_bo(g_bo); ret = drmModeSetCrtc(g_drm_fd, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); if (ret < 0) goto error; g_inited = true; return true; error: gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void) { if (g_inited) return false; g_drm_fd = open("/dev/dri/card0", O_RDWR); if (g_drm_fd < 0) { RARCH_ERR("[KMS/EGL]: Couldn't open DRM device.\n"); goto error; } g_resources = drmModeGetResources(g_drm_fd); if (!g_resources) { RARCH_ERR("[KMS/EGL]: Couldn't get device resources.\n"); goto error; } for (int i = 0; i < g_resources->count_connectors; i++) { g_connector = drmModeGetConnector(g_drm_fd, g_resources->connectors[i]); if (!g_connector) continue; if (g_connector->connection == DRM_MODE_CONNECTED && g_connector->count_modes > 0) break; drmModeFreeConnector(g_connector); g_connector = NULL; } if (!g_connector) { RARCH_ERR("[KMS/EGL]: Couldn't get device connector.\n"); goto error; } for (int i = 0; i < g_resources->count_encoders; i++) { g_encoder = drmModeGetEncoder(g_drm_fd, g_resources->encoders[i]); if (!g_encoder) continue; if (g_encoder->encoder_id == g_connector->encoder_id) break; drmModeFreeEncoder(g_encoder); g_encoder = NULL; } if (!g_encoder) { RARCH_ERR("[KMS/EGL]: Couldn't find DRM encoder.\n"); goto error; } g_drm_mode = &g_connector->modes[0]; g_crtc_id = g_encoder->crtc_id; g_orig_crtc = drmModeGetCrtc(g_drm_fd, g_crtc_id); if (!g_orig_crtc) RARCH_WARN("[KMS/EGL]: Cannot find original CRTC.\n"); g_connector_id = g_connector->connector_id; g_fb_width = g_drm_mode->hdisplay; g_fb_height = g_drm_mode->vdisplay; g_gbm_dev = gbm_create_device(g_drm_fd); g_gbm_surface = gbm_surface_create(g_gbm_dev, g_fb_width, g_fb_height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); if (!g_gbm_surface) { RARCH_ERR("[KMS/EGL]: Couldn't create GBM surface.\n"); goto error; } return true; error: gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void) { const EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; EGLint num_config; EGLint egl_version_major, egl_version_minor; int format = SCREEN_FORMAT_RGBX8888; EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; int usage; usage = SCREEN_USAGE_OPENGL_ES2 | SCREEN_USAGE_ROTATION; RARCH_LOG("Initializing context\n"); if ((g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) { RARCH_ERR("eglGetDisplay failed.\n"); goto error; } if (!eglInitialize(g_egl_dpy, &egl_version_major, &egl_version_minor)) { RARCH_ERR("eglInitialize failed.\n"); goto error; } if (!eglBindAPI(EGL_OPENGL_ES_API)) { RARCH_ERR("eglBindAPI failed.\n"); goto error; } RARCH_LOG("[BLACKBERRY QNX/EGL]: EGL version: %d.%d\n", egl_version_major, egl_version_minor); if (!eglChooseConfig(g_egl_dpy, attribs, &egl_config, 1, &num_config)) { RARCH_ERR("eglChooseConfig failed.\n"); goto error; } if ((g_egl_ctx = eglCreateContext(g_egl_dpy, egl_config, 0, context_attributes)) == EGL_NO_CONTEXT) { RARCH_ERR("eglCreateContext failed.\n"); goto error; } if (screen_create_window(&screen_win, screen_ctx)) { RARCH_ERR("screen_create_window failed:.\n"); goto error; } if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_FORMAT, &format)) { RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_FORMAT] failed.\n"); goto error; } if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage)) { RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_USAGE] failed.\n"); goto error; } if (screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_DISPLAY, (void **)&screen_disp)) { RARCH_ERR("screen_get_window_property_pv [SCREEN_PROPERTY_DISPLAY] failed.\n"); goto error; } int screen_resolution[2]; if (screen_get_display_property_iv(screen_disp, SCREEN_PROPERTY_SIZE, screen_resolution)) { RARCH_ERR("screen_get_window_property_iv [SCREEN_PROPERTY_SIZE] failed.\n"); goto error; } int angle = atoi(getenv("ORIENTATION")); screen_display_mode_t screen_mode; if (screen_get_display_property_pv(screen_disp, SCREEN_PROPERTY_MODE, (void**)&screen_mode)) { RARCH_ERR("screen_get_display_property_pv [SCREEN_PROPERTY_MODE] failed.\n"); goto error; } int size[2]; if (screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, size)) { RARCH_ERR("screen_get_window_property_iv [SCREEN_PROPERTY_BUFFER_SIZE] failed.\n"); goto error; } int buffer_size[2] = {size[0], size[1]}; if ((angle == 0) || (angle == 180)) { if (((screen_mode.width > screen_mode.height) && (size[0] < size[1])) || ((screen_mode.width < screen_mode.height) && (size[0] > size[1]))) { buffer_size[1] = size[0]; buffer_size[0] = size[1]; } } else if ((angle == 90) || (angle == 270)){ if (((screen_mode.width > screen_mode.height) && (size[0] > size[1])) || ((screen_mode.width < screen_mode.height && size[0] < size[1]))) { buffer_size[1] = size[0]; buffer_size[0] = size[1]; } } else { RARCH_ERR("Navigator returned an unexpected orientation angle.\n"); goto error; } if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, buffer_size)) { RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_BUFFER_SIZE] failed.\n"); goto error; } if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ROTATION, &angle)) { RARCH_ERR("screen_set_window_property_iv [SCREEN_PROPERTY_ROTATION] failed.\n"); goto error; } if (screen_create_window_buffers(screen_win, WINDOW_BUFFERS)) { RARCH_ERR("screen_create_window_buffers failed.\n"); goto error; } if (!(g_egl_surf = eglCreateWindowSurface(g_egl_dpy, egl_config, screen_win, 0))) { RARCH_ERR("eglCreateWindowSurface failed.\n"); goto error; } if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) { RARCH_ERR("eglMakeCurrent failed.\n"); goto error; } return true; error: RARCH_ERR("EGL error: %d.\n", eglGetError()); gfx_ctx_destroy(); return false; }
static bool gfx_ctx_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { if (g_inited) return false; int i; int ret = 0; struct drm_fb *fb = NULL; struct sigaction sa = {{0}}; sa.sa_handler = sighandler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); #define EGL_ATTRIBS_BASE \ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \ EGL_RED_SIZE, 1, \ EGL_GREEN_SIZE, 1, \ EGL_BLUE_SIZE, 1, \ EGL_ALPHA_SIZE, 0, \ EGL_DEPTH_SIZE, 0 static const EGLint egl_attribs_gl[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE, }; static const EGLint egl_attribs_gles[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE, }; #ifdef EGL_KHR_create_context static const EGLint egl_attribs_gles3[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, EGL_NONE, }; #endif static const EGLint egl_attribs_vg[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, EGL_NONE, }; const EGLint *attrib_ptr; switch (g_api) { case GFX_CTX_OPENGL_API: attrib_ptr = egl_attribs_gl; break; case GFX_CTX_OPENGL_ES_API: #ifdef EGL_KHR_create_context if (g_major >= 3) attrib_ptr = egl_attribs_gles3; else #endif attrib_ptr = egl_attribs_gles; break; case GFX_CTX_OPENVG_API: attrib_ptr = egl_attribs_vg; break; default: attrib_ptr = NULL; } // Find desired video mode, and use that. // If not fullscreen, we get desired windowed size, which is not appropriate. if ((width == 0 && height == 0) || !fullscreen) g_drm_mode = &g_connector->modes[0]; else { // Try to match g_settings.video.refresh_rate as closely as possible. // Lower resolutions tend to have multiple supported refresh rates as well. float minimum_fps_diff = 0.0f; // Find best match. for (i = 0; i < g_connector->count_modes; i++) { if (width != g_connector->modes[i].hdisplay || height != g_connector->modes[i].vdisplay) continue; if (!g_drm_mode) { g_drm_mode = &g_connector->modes[i]; minimum_fps_diff = g_drm_mode->vrefresh - g_settings.video.refresh_rate; } else { float diff = g_connector->modes[i].vrefresh - g_settings.video.refresh_rate; if (diff < minimum_fps_diff) { g_drm_mode = &g_connector->modes[i]; minimum_fps_diff = diff; } } } } if (!g_drm_mode) { RARCH_ERR("[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", width, height); goto error; } g_fb_width = g_drm_mode->hdisplay; g_fb_height = g_drm_mode->vdisplay; // Create GBM surface. g_gbm_surface = gbm_surface_create(g_gbm_dev, g_fb_width, g_fb_height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); if (!g_gbm_surface) { RARCH_ERR("[KMS/EGL]: Couldn't create GBM surface.\n"); goto error; } g_egl_dpy = eglGetDisplay((EGLNativeDisplayType)g_gbm_dev); if (!g_egl_dpy) { RARCH_ERR("[KMS/EGL]: Couldn't get EGL display.\n"); goto error; } EGLint major, minor; if (!eglInitialize(g_egl_dpy, &major, &minor)) goto error; EGLint n; if (!eglChooseConfig(g_egl_dpy, attrib_ptr, &g_config, 1, &n) || n != 1) goto error; EGLint egl_attribs[16]; EGLint *attr = egl_attribs; attr = egl_fill_attribs(attr); g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, attr != egl_attribs ? egl_attribs : NULL); if (g_egl_ctx == EGL_NO_CONTEXT) goto error; if (g_use_hw_ctx) { g_egl_hw_ctx = eglCreateContext(g_egl_dpy, g_config, g_egl_ctx, attr != egl_attribs ? egl_attribs : NULL); RARCH_LOG("[KMS/EGL]: Created shared context: %p.\n", (void*)g_egl_hw_ctx); if (g_egl_hw_ctx == EGL_NO_CONTEXT) goto error; } g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, (EGLNativeWindowType)g_gbm_surface, NULL); if (!g_egl_surf) goto error; if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) goto error; glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(g_egl_dpy, g_egl_surf); g_bo = gbm_surface_lock_front_buffer(g_gbm_surface); fb = drm_fb_get_from_bo(g_bo); ret = drmModeSetCrtc(g_drm_fd, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); if (ret < 0) goto error; g_inited = true; return true; error: gfx_ctx_destroy(data); return false; }
static bool gfx_ctx_set_video_mode( unsigned width, unsigned height, bool fullscreen) { DWORD style; RECT rect = {0}; HMONITOR hm_to_use = NULL; MONITORINFOEX current_mon; monitor_info(¤t_mon, &hm_to_use); RECT mon_rect = current_mon.rcMonitor; g_resize_width = width; g_resize_height = height; bool windowed_full = g_settings.video.windowed_fullscreen; if (fullscreen) { if (windowed_full) { style = WS_EX_TOPMOST | WS_POPUP; g_resize_width = width = mon_rect.right - mon_rect.left; g_resize_height = height = mon_rect.bottom - mon_rect.top; } else { style = WS_POPUP | WS_VISIBLE; if (!set_fullscreen(width, height, current_mon.szDevice)) goto error; // display settings might have changed, get new coordinates GetMonitorInfo(hm_to_use, (MONITORINFO*)¤t_mon); mon_rect = current_mon.rcMonitor; g_restore_desktop = true; } } else { style = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; rect.right = width; rect.bottom = height; AdjustWindowRect(&rect, style, FALSE); width = rect.right - rect.left; height = rect.bottom - rect.top; } g_hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", style, fullscreen ? mon_rect.left : g_pos_x, fullscreen ? mon_rect.top : g_pos_y, width, height, NULL, NULL, NULL, NULL); if (!g_hwnd) goto error; if (!fullscreen) { SetMenu(g_hwnd, LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MENU))); RECT rcTemp = {0, 0, g_resize_height, 0x7FFF}; // 0x7FFF="Infinite" height SendMessage(g_hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcTemp); // recalculate margin, taking possible menu wrap into account g_resize_height += rcTemp.top + rect.top; // extend by new top margin and substract previous margin SetWindowPos(g_hwnd, NULL, 0, 0, g_resize_width, g_resize_height, SWP_NOMOVE); } if (!fullscreen || windowed_full) { ShowWindow(g_hwnd, SW_RESTORE); UpdateWindow(g_hwnd); SetForegroundWindow(g_hwnd); SetFocus(g_hwnd); } show_cursor(!fullscreen); // Wait until GL context is created (or failed to do so ...) MSG msg; while (!g_inited && !g_quit && GetMessage(&msg, g_hwnd, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (g_quit) goto error; p_swap_interval = (BOOL (APIENTRY *)(int))wglGetProcAddress("wglSwapIntervalEXT"); gfx_ctx_swap_interval(g_interval); driver.display_type = RARCH_DISPLAY_WIN32; driver.video_display = 0; driver.video_window = (uintptr_t)g_hwnd; return true; error: gfx_ctx_destroy(); return false; }
static bool gfx_ctx_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { struct sigaction sa = {{0}}; sa.sa_handler = sighandler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); int x_off = 0; int y_off = 0; bool windowed_full = g_settings.video.windowed_fullscreen; bool true_full = false; int (*old_handler)(Display*, XErrorEvent*) = NULL; XSetWindowAttributes swa = {0}; XVisualInfo *vi = glXGetVisualFromFBConfig(g_dpy, g_fbc); if (!vi) goto error; swa.colormap = g_cmap = XCreateColormap(g_dpy, RootWindow(g_dpy, vi->screen), vi->visual, AllocNone); swa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask; swa.override_redirect = fullscreen ? True : False; if (fullscreen && !windowed_full) { if (x11_enter_fullscreen(g_dpy, width, height, &g_desktop_mode)) { g_should_reset_mode = true; true_full = true; } else RARCH_ERR("[GLX]: Entering true fullscreen failed. Will attempt windowed mode.\n"); } if (g_settings.video.monitor_index) g_screen = g_settings.video.monitor_index - 1; #ifdef HAVE_XINERAMA if (fullscreen || g_screen != 0) { unsigned new_width = width; unsigned new_height = height; if (x11_get_xinerama_coord(g_dpy, g_screen, &x_off, &y_off, &new_width, &new_height)) RARCH_LOG("[GLX]: Using Xinerama on screen #%u.\n", g_screen); else RARCH_LOG("[GLX]: Xinerama is not active on screen.\n"); if (fullscreen) { width = new_width; height = new_height; } } #endif RARCH_LOG("[GLX]: X = %d, Y = %d, W = %u, H = %u.\n", x_off, y_off, width, height); g_win = XCreateWindow(g_dpy, RootWindow(g_dpy, vi->screen), x_off, y_off, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | (true_full ? CWOverrideRedirect : 0), &swa); XSetWindowBackground(g_dpy, g_win, 0); g_glx_win = glXCreateWindow(g_dpy, g_fbc, g_win, 0); x11_set_window_attr(g_dpy, g_win); if (fullscreen) x11_show_mouse(g_dpy, g_win, false); if (true_full) { RARCH_LOG("[GLX]: Using true fullscreen.\n"); XMapRaised(g_dpy, g_win); } else if (fullscreen) // We attempted true fullscreen, but failed. Attempt using windowed fullscreen. { XMapRaised(g_dpy, g_win); RARCH_LOG("[GLX]: Using windowed fullscreen.\n"); // We have to move the window to the screen we want to go fullscreen on first. // x_off and y_off usually get ignored in XCreateWindow(). x11_move_window(g_dpy, g_win, x_off, y_off, width, height); x11_windowed_fullscreen(g_dpy, g_win); } else { XMapWindow(g_dpy, g_win); // If we want to map the window on a different screen, we'll have to do it by force. // Otherwise, we should try to let the window manager sort it out. // x_off and y_off usually get ignored in XCreateWindow(). if (g_screen) x11_move_window(g_dpy, g_win, x_off, y_off, width, height); } XEvent event; XIfEvent(g_dpy, &event, glx_wait_notify, NULL); if (!g_ctx) { if (g_core || g_debug) { int attribs[16]; int *aptr = attribs; if (g_core) { *aptr++ = GLX_CONTEXT_MAJOR_VERSION_ARB; *aptr++ = g_major; *aptr++ = GLX_CONTEXT_MINOR_VERSION_ARB; *aptr++ = g_minor; // Technically, we don't have core/compat until 3.2. // Version 3.1 is either compat or not depending on GL_ARB_compatibility. if ((g_major * 1000 + g_minor) >= 3002) { *aptr++ = GLX_CONTEXT_PROFILE_MASK_ARB; *aptr++ = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; } } if (g_debug) { *aptr++ = GLX_CONTEXT_FLAGS_ARB; *aptr++ = GLX_CONTEXT_DEBUG_BIT_ARB; } *aptr = None; g_ctx = glx_create_context_attribs(g_dpy, g_fbc, NULL, True, attribs); if (g_use_hw_ctx) { RARCH_LOG("[GLX]: Creating shared HW context.\n"); g_hw_ctx = glx_create_context_attribs(g_dpy, g_fbc, g_ctx, True, attribs); if (!g_hw_ctx) RARCH_ERR("[GLX]: Failed to create new shared context.\n"); } } else { g_ctx = glXCreateNewContext(g_dpy, g_fbc, GLX_RGBA_TYPE, 0, True); if (g_use_hw_ctx) { g_hw_ctx = glXCreateNewContext(g_dpy, g_fbc, GLX_RGBA_TYPE, g_ctx, True); if (!g_hw_ctx) RARCH_ERR("[GLX]: Failed to create new shared context.\n"); } } if (!g_ctx) { RARCH_ERR("[GLX]: Failed to create new context.\n"); goto error; } } else { driver.video_cache_context_ack = true; RARCH_LOG("[GLX]: Using cached GL context.\n"); } glXMakeContextCurrent(g_dpy, g_glx_win, g_glx_win, g_ctx); XSync(g_dpy, False); g_quit_atom = XInternAtom(g_dpy, "WM_DELETE_WINDOW", False); if (g_quit_atom) XSetWMProtocols(g_dpy, g_win, &g_quit_atom, 1); int val; glXGetConfig(g_dpy, vi, GLX_DOUBLEBUFFER, &val); g_is_double = val; if (g_is_double) { const char *swap_func = NULL; g_pglSwapIntervalEXT = (void (*)(Display*, GLXDrawable, int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT"); g_pglSwapInterval = (int (*)(int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalMESA"); if (g_pglSwapIntervalEXT) swap_func = "glXSwapIntervalEXT"; else if (g_pglSwapInterval) swap_func = "glXSwapIntervalMESA"; if (!g_pglSwapInterval && !g_pglSwapIntervalEXT) RARCH_WARN("[GLX]: Cannot find swap interval call.\n"); else RARCH_LOG("[GLX]: Found swap function: %s.\n", swap_func); } else RARCH_WARN("[GLX]: Context is not double buffered!.\n"); gfx_ctx_swap_interval(data, g_interval); // This can blow up on some drivers. It's not fatal, so override errors for this call. old_handler = XSetErrorHandler(nul_handler); XSetInputFocus(g_dpy, g_win, RevertToNone, CurrentTime); XSync(g_dpy, False); XSetErrorHandler(old_handler); XFree(vi); g_has_focus = true; g_inited = true; if (!x11_create_input_context(g_dpy, g_win, &g_xim, &g_xic)) goto error; driver.display_type = RARCH_DISPLAY_X11; driver.video_display = (uintptr_t)g_dpy; driver.video_window = (uintptr_t)g_win; g_true_full = true_full; return true; error: if (vi) XFree(vi); gfx_ctx_destroy(data); return false; }
static bool gfx_ctx_set_video_mode( unsigned width, unsigned height, bool fullscreen) { struct sigaction sa = {{0}}; sa.sa_handler = sighandler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); XVisualInfo temp = {0}; XSetWindowAttributes swa = {0}; XVisualInfo *vi = NULL; bool windowed_full = g_settings.video.windowed_fullscreen; bool true_full = false; int x_off = 0; int y_off = 0; int (*old_handler)(Display*, XErrorEvent*) = NULL; EGLint vid; if (!eglGetConfigAttrib(g_egl_dpy, g_config, EGL_NATIVE_VISUAL_ID, &vid)) goto error; temp.visualid = vid; EGLint num_visuals; vi = XGetVisualInfo(g_dpy, VisualIDMask, &temp, &num_visuals); if (!vi) goto error; swa.colormap = g_cmap = XCreateColormap(g_dpy, RootWindow(g_dpy, vi->screen), vi->visual, AllocNone); swa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask; swa.override_redirect = fullscreen ? True : False; if (fullscreen && !windowed_full) { if (x11_enter_fullscreen(g_dpy, width, height, &g_desktop_mode)) { g_should_reset_mode = true; true_full = true; } else RARCH_ERR("[X/EGL]: Entering true fullscreen failed. Will attempt windowed mode.\n"); } if (g_settings.video.monitor_index) g_screen = g_settings.video.monitor_index - 1; #ifdef HAVE_XINERAMA if (fullscreen || g_screen != 0) { unsigned new_width = width; unsigned new_height = height; if (x11_get_xinerama_coord(g_dpy, g_screen, &x_off, &y_off, &new_width, &new_height)) RARCH_LOG("[X/EGL]: Using Xinerama on screen #%u.\n", g_screen); else RARCH_LOG("[X/EGL]: Xinerama is not active on screen.\n"); if (fullscreen) { width = new_width; height = new_height; } } #endif RARCH_LOG("[X/EGL]: X = %d, Y = %d, W = %u, H = %u.\n", x_off, y_off, width, height); g_win = XCreateWindow(g_dpy, RootWindow(g_dpy, vi->screen), x_off, y_off, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | (true_full ? CWOverrideRedirect : 0), &swa); XSetWindowBackground(g_dpy, g_win, 0); // GLES 2.0. Don't use for any other API. static const EGLint egl_ctx_gles_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, }; g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, (g_api == GFX_CTX_OPENGL_ES_API) ? egl_ctx_gles_attribs : NULL); RARCH_LOG("[X/EGL]: Created context: %p.\n", (void*)g_egl_ctx); if (!g_egl_ctx) goto error; g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, (EGLNativeWindowType)g_win, NULL); if (!g_egl_surf) goto error; if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) goto error; RARCH_LOG("[X/EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); x11_set_window_attr(g_dpy, g_win); if (fullscreen) x11_show_mouse(g_dpy, g_win, false); if (true_full) { RARCH_LOG("[X/EGL]: Using true fullscreen.\n"); XMapRaised(g_dpy, g_win); } else if (fullscreen) // We attempted true fullscreen, but failed. Attempt using windowed fullscreen. { XMapRaised(g_dpy, g_win); RARCH_LOG("[X/EGL]: Using windowed fullscreen.\n"); // We have to move the window to the screen we want to go fullscreen on first. // x_off and y_off usually get ignored in XCreateWindow(). x11_move_window(g_dpy, g_win, x_off, y_off, width, height); x11_windowed_fullscreen(g_dpy, g_win); } else { XMapWindow(g_dpy, g_win); // If we want to map the window on a different screen, we'll have to do it by force. // Otherwise, we should try to let the window manager sort it out. // x_off and y_off usually get ignored in XCreateWindow(). if (g_screen) x11_move_window(g_dpy, g_win, x_off, y_off, width, height); } XEvent event; XIfEvent(g_dpy, &event, egl_wait_notify, NULL); g_quit_atom = XInternAtom(g_dpy, "WM_DELETE_WINDOW", False); if (g_quit_atom) XSetWMProtocols(g_dpy, g_win, &g_quit_atom, 1); gfx_ctx_swap_interval(g_interval); // This can blow up on some drivers. It's not fatal, so override errors for this call. old_handler = XSetErrorHandler(nul_handler); XSetInputFocus(g_dpy, g_win, RevertToNone, CurrentTime); XSync(g_dpy, False); XSetErrorHandler(old_handler); XFree(vi); g_has_focus = true; g_inited = true; driver.display_type = RARCH_DISPLAY_X11; driver.video_display = (uintptr_t)g_dpy; driver.video_window = (uintptr_t)g_win; g_true_full = true_full; return true; error: if (vi) XFree(vi); gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void) { RARCH_LOG("gfx_ctx_init().\n"); const EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; EGLint num_config; EGLint egl_version_major, egl_version_minor; EGLint format; EGLint width; EGLint height; GLfloat ratio; EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; RARCH_LOG("Initializing context\n"); if ((g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) { RARCH_ERR("eglGetDisplay failed.\n"); goto error; } if (!eglInitialize(g_egl_dpy, &egl_version_major, &egl_version_minor)) { RARCH_ERR("eglInitialize failed.\n"); goto error; } RARCH_LOG("[ANDROID/EGL]: EGL version: %d.%d\n", egl_version_major, egl_version_minor); if (!eglChooseConfig(g_egl_dpy, attribs, &g_config, 1, &num_config)) { RARCH_ERR("eglChooseConfig failed.\n"); goto error; } int var = eglGetConfigAttrib(g_egl_dpy, g_config, EGL_NATIVE_VISUAL_ID, &format); if (!var) { RARCH_ERR("eglGetConfigAttrib failed: %d.\n", var); goto error; } ANativeWindow_setBuffersGeometry(g_android.app->window, 0, 0, format); if (!(g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, g_android.app->window, 0))) { RARCH_ERR("eglCreateWindowSurface failed.\n"); goto error; } if (!(g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, 0, context_attributes))) { RARCH_ERR("eglCreateContext failed.\n"); goto error; } if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) { RARCH_ERR("eglMakeCurrent failed.\n"); goto error; } if (!eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_WIDTH, &width) || !eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_HEIGHT, &height)) { RARCH_ERR("eglQuerySurface failed.\n"); goto error; } if (g_extern.lifecycle_state & (1ULL << RARCH_REENTRANT)) { RARCH_LOG("[ANDROID/EGL]: Setting up reentrant state.\n"); gfx_ctx_orientation_update(); } return true; error: RARCH_ERR("EGL error: %d.\n", eglGetError()); gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void) { if (g_inited) return false; XInitThreads(); #define EGL_ATTRIBS_BASE \ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \ EGL_RED_SIZE, 1, \ EGL_GREEN_SIZE, 1, \ EGL_BLUE_SIZE, 1, \ EGL_ALPHA_SIZE, 0, \ EGL_DEPTH_SIZE, 0 static const EGLint egl_attribs_gl[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE, }; static const EGLint egl_attribs_gles[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE, }; static const EGLint egl_attribs_vg[] = { EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, EGL_NONE, }; const EGLint *attrib_ptr; switch (g_api) { case GFX_CTX_OPENGL_API: attrib_ptr = egl_attribs_gl; break; case GFX_CTX_OPENGL_ES_API: attrib_ptr = egl_attribs_gles; break; case GFX_CTX_OPENVG_API: attrib_ptr = egl_attribs_vg; break; default: attrib_ptr = NULL; } g_quit = 0; g_dpy = XOpenDisplay(NULL); if (!g_dpy) goto error; g_egl_dpy = eglGetDisplay((EGLNativeDisplayType)g_dpy); if (!g_egl_dpy) { RARCH_ERR("[X/EGL]: EGL display not available.\n"); goto error; } EGLint egl_major, egl_minor; if (!eglInitialize(g_egl_dpy, &egl_major, &egl_minor)) { RARCH_ERR("[X/EGL]: Unable to initialize EGL.\n"); goto error; } RARCH_LOG("[X/EGL]: EGL version: %d.%d\n", egl_major, egl_minor); EGLint num_configs; if (!eglChooseConfig(g_egl_dpy, attrib_ptr, &g_config, 1, &num_configs)) { RARCH_ERR("[X/EGL]: eglChooseConfig failed with %x.\n", eglGetError()); goto error; } if (num_configs == 0 || !g_config) { RARCH_ERR("[X/EGL]: No EGL configurations available.\n"); goto error; } return true; error: gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void) { RARCH_LOG("[VC/EGL]: Initializing...\n"); if (g_inited) { RARCH_ERR("[VC/EGL]: Attempted to re-initialize driver.\n"); return false; } EGLint num_config; static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_UPDATE_HANDLE_T dispman_update; DISPMANX_MODEINFO_T dispman_modeinfo; VC_RECT_T dst_rect; VC_RECT_T src_rect; static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; bcm_host_init(); // get an EGL display connection g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!g_egl_dpy) goto error; // initialize the EGL display connection if (!eglInitialize(g_egl_dpy, NULL, NULL)) goto error; // get an appropriate EGL frame buffer configuration if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_config, 1, &num_config)) goto error; // create an EGL rendering context g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, (g_api == GFX_CTX_OPENGL_ES_API) ? context_attributes : NULL); if (!g_egl_ctx) goto error; // create an EGL window surface if (graphics_get_display_size(0 /* LCD */, &g_fb_width, &g_fb_height) < 0) goto error; dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = g_fb_width; dst_rect.height = g_fb_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = g_fb_width << 16; src_rect.height = g_fb_height << 16; dispman_display = vc_dispmanx_display_open(0 /* LCD */); vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo); dispman_update = vc_dispmanx_update_start(0); VC_DISPMANX_ALPHA_T alpha; alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; alpha.opacity = 255; alpha.mask = 0; dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0 /*clamp*/, DISPMANX_NO_ROTATE); nativewindow.element = dispman_element; nativewindow.width = g_fb_width; nativewindow.height = g_fb_height; vc_dispmanx_update_submit_sync(dispman_update); g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, &nativewindow, NULL); if (!g_egl_surf) goto error; // connect the context to the surface if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) goto error; return true; error: gfx_ctx_destroy(); return false; }
static void *vg_init(const video_info_t *video, const input_driver_t **input, void **input_data) { unsigned temp_width = 0, temp_height = 0; VGfloat clearColor[4] = {0, 0, 0, 1}; settings_t *settings = config_get_ptr(); const gfx_ctx_driver_t *ctx = NULL; vg_t *vg = (vg_t*)calloc(1, sizeof(vg_t)); if (!vg) goto error; ctx = gfx_ctx_init_first(vg, settings->video.context_driver, GFX_CTX_OPENVG_API, 0, 0, false); if (!ctx) goto error; gfx_ctx_set(ctx); gfx_ctx_get_video_size(&temp_width, &temp_height); RARCH_LOG("Detecting screen resolution %ux%u.\n", temp_width, temp_height); if (temp_width != 0 && temp_height != 0) video_driver_set_size(&temp_width, &temp_height); gfx_ctx_swap_interval(video->vsync ? 1 : 0); gfx_ctx_update_window_title(); vg->mTexType = video->rgb32 ? VG_sXRGB_8888 : VG_sRGB_565; vg->keep_aspect = video->force_aspect; unsigned win_width = video->width; unsigned win_height = video->height; if (video->fullscreen && (win_width == 0) && (win_height == 0)) { video_driver_get_size(&temp_width, &temp_height); win_width = temp_width; win_height = temp_height; } if (!gfx_ctx_set_video_mode(win_width, win_height, video->fullscreen)) goto error; video_driver_get_size(&temp_width, &temp_height); temp_width = 0; temp_height = 0; gfx_ctx_get_video_size(&temp_width, &temp_height); vg->should_resize = true; if (temp_width != 0 && temp_height != 0) { RARCH_LOG("Verified window resolution %ux%u.\n", temp_width, temp_height); video_driver_set_size(&temp_width, &temp_height); } video_driver_get_size(&temp_width, &temp_height); vg->mScreenAspect = (float)temp_width / temp_height; gfx_ctx_translate_aspect(&vg->mScreenAspect, temp_width, temp_height); vgSetfv(VG_CLEAR_COLOR, 4, clearColor); vg->mTextureWidth = vg->mTextureHeight = video->input_scale * RARCH_SCALE_BASE; vg->mImage = vgCreateImage(vg->mTexType, vg->mTextureWidth, vg->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); vg_set_nonblock_state(vg, !video->vsync); gfx_ctx_input_driver(input, input_data); if (settings->video.font_enable && font_renderer_create_default(&vg->font_driver, &vg->mFontRenderer, *settings->video.font_path ? settings->video.font_path : NULL, settings->video.font_size)) { vg->mFont = vgCreateFont(0); if (vg->mFont != VG_INVALID_HANDLE) { vg->mFontsOn = true; vg->mFontHeight = settings->video.font_size; vg->mPaintFg = vgCreatePaint(); vg->mPaintBg = vgCreatePaint(); VGfloat paintFg[] = { settings->video.msg_color_r, settings->video.msg_color_g, settings->video.msg_color_b, 1.0f }; VGfloat paintBg[] = { settings->video.msg_color_r / 2.0f, settings->video.msg_color_g / 2.0f, settings->video.msg_color_b / 2.0f, 0.5f }; vgSetParameteri(vg->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); vgSetParameterfv(vg->mPaintFg, VG_PAINT_COLOR, 4, paintFg); vgSetParameteri(vg->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); vgSetParameterfv(vg->mPaintBg, VG_PAINT_COLOR, 4, paintBg); } } if (vg_query_extension("KHR_EGL_image") && gfx_ctx_image_buffer_init(video)) { pvgCreateEGLImageTargetKHR = (PFNVGCREATEEGLIMAGETARGETKHRPROC)gfx_ctx_get_proc_address("vgCreateEGLImageTargetKHR"); if (pvgCreateEGLImageTargetKHR) { RARCH_LOG("[VG] Using EGLImage buffer\n"); vg->mEglImageBuf = true; } } #if 0 const char *ext = (const char*)vgGetString(VG_EXTENSIONS); if (ext) RARCH_LOG("[VG] Supported extensions: %s\n", ext); #endif return vg; error: if (vg) free(vg); gfx_ctx_destroy(ctx); return NULL; }
static void *gl_init(const video_info_t *video, const input_driver_t **input, void **input_data) { #ifdef _WIN32 gfx_set_dwm(); #endif #ifdef RARCH_CONSOLE if (driver.video_data) return driver.video_data; #endif gl_t *gl = (gl_t*)calloc(1, sizeof(gl_t)); if (!gl) return NULL; if (!gfx_ctx_init()) { free(gl); return NULL; } unsigned full_x = 0, full_y = 0; gfx_ctx_get_video_size(&full_x, &full_y); RARCH_LOG("Detecting resolution %ux%u.\n", full_x, full_y); gfx_ctx_set_swap_interval(video->vsync ? 1 : 0, false); unsigned win_width = video->width; unsigned win_height = video->height; if (video->fullscreen && (win_width == 0) && (win_height == 0)) { win_width = full_x; win_height = full_y; } if (!gfx_ctx_set_video_mode(win_width, win_height, g_settings.video.force_16bit ? 15 : 0, video->fullscreen)) { free(gl); return NULL; } #ifndef RARCH_CONSOLE gfx_ctx_update_window_title(true); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif #if (defined(HAVE_XML) || defined(HAVE_CG)) && defined(_WIN32) // Win32 GL lib doesn't have some functions needed for XML shaders. // Need to load dynamically :( if (!load_gl_proc()) { gfx_ctx_destroy(); free(gl); return NULL; } #endif gl->vsync = video->vsync; gl->fullscreen = video->fullscreen; gl->full_x = full_x; gl->full_y = full_y; gl->win_width = win_width; gl->win_height = win_height; RARCH_LOG("GL: Using resolution %ux%u\n", gl->win_width, gl->win_height); #if defined(HAVE_CG_MENU) && defined(RARCH_CONSOLE) RARCH_LOG("Initializing menu shader ...\n"); gl_cg_set_menu_shader(default_paths.menu_shader_file); #endif if (!gl_shader_init()) { RARCH_ERR("Shader init failed.\n"); gfx_ctx_destroy(); free(gl); return NULL; } RARCH_LOG("GL: Loaded %u program(s).\n", gl_shader_num()); #ifdef HAVE_FBO // Set up render to texture. gl_init_fbo(gl, RARCH_SCALE_BASE * video->input_scale, RARCH_SCALE_BASE * video->input_scale); #endif gl->keep_aspect = video->force_aspect; // Apparently need to set viewport for passes when we aren't using FBOs. gl_shader_use(0); gl_set_viewport(gl, gl->win_width, gl->win_height, false, true); gl_shader_use(1); gl_set_viewport(gl, gl->win_width, gl->win_height, false, true); bool force_smooth = false; if (gl_shader_filter_type(1, &force_smooth)) gl->tex_filter = force_smooth ? GL_LINEAR : GL_NEAREST; else gl->tex_filter = video->smooth ? GL_LINEAR : GL_NEAREST; gl->texture_type = RARCH_GL_TEXTURE_TYPE; gl->texture_fmt = video->rgb32 ? RARCH_GL_FORMAT32 : RARCH_GL_FORMAT16; gl->base_size = video->rgb32 ? sizeof(uint32_t) : sizeof(uint16_t); glEnable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glClearColor(0, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vertex_ptr); memcpy(gl->tex_coords, tex_coords, sizeof(tex_coords)); glTexCoordPointer(2, GL_FLOAT, 0, gl->tex_coords); glColorPointer(4, GL_FLOAT, 0, white_color); set_lut_texture_coords(tex_coords); gl->tex_w = RARCH_SCALE_BASE * video->input_scale; gl->tex_h = RARCH_SCALE_BASE * video->input_scale; #ifdef HAVE_OPENGL_TEXREF glGenBuffers(1, &gl->pbo); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, gl->pbo); glBufferData(GL_TEXTURE_REFERENCE_BUFFER_SCE, gl->tex_w * gl->tex_h * gl->base_size * TEXTURES, NULL, GL_STREAM_DRAW); #endif // Empty buffer that we use to clear out the texture with on res change. gl->empty_buf = calloc(gl->tex_w * gl->tex_h, gl->base_size); gl_init_textures(gl); for (unsigned i = 0; i < TEXTURES; i++) { gl->last_width[i] = gl->tex_w; gl->last_height[i] = gl->tex_h; } for (unsigned i = 0; i < TEXTURES; i++) { gl->prev_info[i].tex = gl->texture[(gl->tex_index - (i + 1)) & TEXTURES_MASK]; gl->prev_info[i].input_size[0] = gl->tex_w; gl->prev_info[i].tex_size[0] = gl->tex_w; gl->prev_info[i].input_size[1] = gl->tex_h; gl->prev_info[i].tex_size[1] = gl->tex_h; memcpy(gl->prev_info[i].coord, tex_coords, sizeof(tex_coords)); } gfx_ctx_input_driver(input, input_data); gl_init_font(gl, g_settings.video.font_path, g_settings.video.font_size); if (!gl_check_error()) { gfx_ctx_destroy(); free(gl); return NULL; } return gl; }
static bool gfx_ctx_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { DWORD style; RECT rect = {0}; HMONITOR hm_to_use = NULL; MONITORINFOEX current_mon; monitor_info(¤t_mon, &hm_to_use); RECT mon_rect = current_mon.rcMonitor; g_resize_width = width; g_resize_height = height; bool windowed_full = g_settings.video.windowed_fullscreen; if (fullscreen) { if (windowed_full) { style = WS_EX_TOPMOST | WS_POPUP; g_resize_width = width = mon_rect.right - mon_rect.left; g_resize_height = height = mon_rect.bottom - mon_rect.top; } else { style = WS_POPUP | WS_VISIBLE; if (!set_fullscreen(width, height, current_mon.szDevice)) goto error; // display settings might have changed, get new coordinates GetMonitorInfo(hm_to_use, (MONITORINFO*)¤t_mon); mon_rect = current_mon.rcMonitor; g_restore_desktop = true; } } else { style = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; rect.right = width; rect.bottom = height; AdjustWindowRect(&rect, style, FALSE); width = rect.right - rect.left; height = rect.bottom - rect.top; } g_hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", style, fullscreen ? mon_rect.left : g_pos_x, fullscreen ? mon_rect.top : g_pos_y, width, height, NULL, NULL, NULL, NULL); if (!g_hwnd) goto error; if (!fullscreen || windowed_full) { ShowWindow(g_hwnd, SW_RESTORE); UpdateWindow(g_hwnd); SetForegroundWindow(g_hwnd); SetFocus(g_hwnd); } show_cursor(!fullscreen); // Wait until GL context is created (or failed to do so ...) MSG msg; while (!g_inited && !g_quit && GetMessage(&msg, g_hwnd, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (g_quit) goto error; p_swap_interval = (BOOL (APIENTRY *)(int))wglGetProcAddress("wglSwapIntervalEXT"); gfx_ctx_swap_interval(data, g_interval); driver.display_type = RARCH_DISPLAY_WIN32; driver.video_display = 0; driver.video_window = (uintptr_t)g_hwnd; return true; error: gfx_ctx_destroy(data); return false; }
static bool gfx_ctx_set_video_mode( unsigned width, unsigned height, bool fullscreen) { struct sigaction sa = {{0}}; sa.sa_handler = sighandler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); int x_off = 0; int y_off = 0; bool windowed_full = g_settings.video.windowed_fullscreen; bool true_full = false; XSetWindowAttributes swa = {0}; XVisualInfo *vi = glXGetVisualFromFBConfig(g_dpy, g_fbc); if (!vi) goto error; swa.colormap = g_cmap = XCreateColormap(g_dpy, RootWindow(g_dpy, vi->screen), vi->visual, AllocNone); swa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask; swa.override_redirect = fullscreen ? True : False; if (fullscreen && !windowed_full) { if (x11_enter_fullscreen(g_dpy, width, height, &g_desktop_mode)) { g_should_reset_mode = true; true_full = true; } else RARCH_ERR("[GLX]: Entering true fullscreen failed. Will attempt windowed mode.\n"); } if (g_settings.video.monitor_index) g_screen = g_settings.video.monitor_index - 1; #ifdef HAVE_XINERAMA if (fullscreen || g_screen != 0) { unsigned new_width = width; unsigned new_height = height; if (x11_get_xinerama_coord(g_dpy, g_screen, &x_off, &y_off, &new_width, &new_height)) RARCH_LOG("[GLX]: Using Xinerama on screen #%u.\n", g_screen); else RARCH_LOG("[GLX]: Xinerama is not active on screen.\n"); if (fullscreen) { width = new_width; height = new_height; } } #endif RARCH_LOG("[GLX]: X = %d, Y = %d, W = %u, H = %u.\n", x_off, y_off, width, height); g_win = XCreateWindow(g_dpy, RootWindow(g_dpy, vi->screen), x_off, y_off, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | (true_full ? CWOverrideRedirect : 0), &swa); XSetWindowBackground(g_dpy, g_win, 0); gfx_ctx_update_window_title(true); x11_set_window_attr(g_dpy, g_win); if (fullscreen) x11_hide_mouse(g_dpy, g_win); if (true_full) { RARCH_LOG("[GLX]: Using true fullscreen.\n"); XMapRaised(g_dpy, g_win); } else if (fullscreen) // We attempted true fullscreen, but failed. Attempt using windowed fullscreen. { XMapRaised(g_dpy, g_win); RARCH_LOG("[GLX]: Using windowed fullscreen.\n"); // We have to move the window to the screen we want to go fullscreen on first. // x_off and y_off usually get ignored in XCreateWindow(). x11_move_window(g_dpy, g_win, x_off, y_off, width, height); x11_windowed_fullscreen(g_dpy, g_win); } else { XMapWindow(g_dpy, g_win); // If we want to map the window on a different screen, we'll have to do it by force. // Otherwise, we should try to let the window manager sort it out. // x_off and y_off usually get ignored in XCreateWindow(). if (g_screen) x11_move_window(g_dpy, g_win, x_off, y_off, width, height); } XEvent event; XIfEvent(g_dpy, &event, glx_wait_notify, NULL); XSetInputFocus(g_dpy, g_win, RevertToNone, CurrentTime); g_ctx = glXCreateNewContext(g_dpy, g_fbc, GLX_RGBA_TYPE, 0, True); if (!g_ctx) { RARCH_ERR("[GLX]: Failed to create new context.\n"); goto error; } glXMakeCurrent(g_dpy, g_win, g_ctx); XSync(g_dpy, False); g_quit_atom = XInternAtom(g_dpy, "WM_DELETE_WINDOW", False); if (g_quit_atom) XSetWMProtocols(g_dpy, g_win, &g_quit_atom, 1); int val; glXGetConfig(g_dpy, vi, GLX_DOUBLEBUFFER, &val); g_is_double = val; if (g_is_double) { if (!g_pglSwapInterval) g_pglSwapInterval = (int (*)(int))glXGetProcAddress((const GLubyte*)"glXSwapInterval"); if (!g_pglSwapInterval) g_pglSwapInterval = (int (*)(int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalMESA"); if (!g_pglSwapInterval) g_pglSwapInterval = (int (*)(int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalSGI"); if (!g_pglSwapInterval) RARCH_WARN("[GLX]: Cannot find swap interval call.\n"); } else RARCH_WARN("[GLX]: Context is not double buffered!.\n"); gfx_ctx_swap_interval(g_interval); XFree(vi); g_has_focus = true; g_inited = true; driver.display_type = RARCH_DISPLAY_X11; driver.video_display = (uintptr_t)g_dpy; driver.video_window = (uintptr_t)g_win; g_true_full = true_full; return true; error: if (vi) XFree(vi); gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void *data) { if (g_inited) return false; XInitThreads(); static const int visual_attribs[] = { GLX_X_RENDERABLE , True, GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, GLX_RENDER_TYPE , GLX_RGBA_BIT, GLX_DOUBLEBUFFER , True, GLX_RED_SIZE , 8, GLX_GREEN_SIZE , 8, GLX_BLUE_SIZE , 8, GLX_ALPHA_SIZE , 8, GLX_DEPTH_SIZE , 0, GLX_STENCIL_SIZE , 0, None }; GLXFBConfig *fbcs = NULL; g_quit = 0; if (!g_dpy) g_dpy = XOpenDisplay(NULL); if (!g_dpy) goto error; int major, minor; glXQueryVersion(g_dpy, &major, &minor); // GLX 1.3+ minimum required. if ((major * 1000 + minor) < 1003) goto error; glx_create_context_attribs = (glXCreateContextAttribsARBProc)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); #ifdef GL_DEBUG g_debug = true; #else g_debug = g_extern.system.hw_render_callback.debug_context; #endif g_core = (g_major * 1000 + g_minor) >= 3001; // Have to use ContextAttribs if ((g_core || g_debug) && !glx_create_context_attribs) goto error; int nelements; fbcs = glXChooseFBConfig(g_dpy, DefaultScreen(g_dpy), visual_attribs, &nelements); if (!fbcs) goto error; if (!nelements) { XFree(fbcs); goto error; } g_fbc = fbcs[0]; XFree(fbcs); return true; error: gfx_ctx_destroy(data); return false; }
static bool gfx_ctx_init(void) { if (g_inited) return false; static const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos", NULL }; for (int i = 0; modules[i]; i++) { RARCH_LOG("[KMS/EGL]: Trying to load module %s ...\n", modules[i]); g_drm_fd = drmOpen(modules[i], NULL); if (g_drm_fd >= 0) { RARCH_LOG("[KMS/EGL]: Found module %s.\n", modules[i]); break; } } if (g_drm_fd < 0) { RARCH_ERR("[KMS/EGL]: Couldn't open DRM device.\n"); goto error; } g_resources = drmModeGetResources(g_drm_fd); if (!g_resources) { RARCH_ERR("[KMS/EGL]: Couldn't get device resources.\n"); goto error; } for (int i = 0; i < g_resources->count_connectors; i++) { g_connector = drmModeGetConnector(g_drm_fd, g_resources->connectors[i]); if (g_connector->connection == DRM_MODE_CONNECTED) break; drmModeFreeConnector(g_connector); g_connector = NULL; } // TODO: Figure out what index for crtcs to use ... g_orig_crtc = drmModeGetCrtc(g_drm_fd, g_resources->crtcs[0]); if (!g_orig_crtc) RARCH_WARN("[KMS/EGL]: Cannot find original CRTC.\n"); if (!g_connector) { RARCH_ERR("[KMS/EGL]: Couldn't get device connector.\n"); goto error; } for (int i = 0, area = 0; i < g_connector->count_modes; i++) { drmModeModeInfo *current_mode = &g_connector->modes[i]; int current_area = current_mode->hdisplay * current_mode->vdisplay; if (current_area > area) { g_drm_mode = current_mode; area = current_area; } } if (!g_drm_mode) { RARCH_ERR("[KMS/EGL]: Couldn't find DRM mode.\n"); goto error; } for (int i = 0; i < g_resources->count_encoders; i++) { g_encoder = drmModeGetEncoder(g_drm_fd, g_resources->encoders[i]); if (g_encoder->encoder_id == g_connector->encoder_id) break; drmModeFreeEncoder(g_encoder); g_encoder = NULL; } if (!g_encoder) { RARCH_ERR("[KMS/EGL]: Couldn't find DRM encoder.\n"); goto error; } g_crtc_id = g_encoder->crtc_id; g_connector_id = g_connector->connector_id; g_fb_width = g_drm_mode->hdisplay; g_fb_height = g_drm_mode->vdisplay; g_gbm_dev = gbm_create_device(g_drm_fd); g_gbm_surface = gbm_surface_create(g_gbm_dev, g_fb_width, g_fb_height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); if (!g_gbm_surface) { RARCH_ERR("[KMS/EGL]: Couldn't create GBM surface.\n"); goto error; } return true; error: gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void) { struct android_app *android_app = (struct android_app*)g_android; const EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; EGLint num_config; EGLint egl_version_major, egl_version_minor; EGLint format; EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; RARCH_LOG("Initializing context\n"); if ((g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) { RARCH_ERR("eglGetDisplay failed.\n"); goto error; } if (!eglInitialize(g_egl_dpy, &egl_version_major, &egl_version_minor)) { RARCH_ERR("eglInitialize failed.\n"); goto error; } RARCH_LOG("[ANDROID/EGL]: EGL version: %d.%d\n", egl_version_major, egl_version_minor); if (!eglChooseConfig(g_egl_dpy, attribs, &g_config, 1, &num_config)) { RARCH_ERR("eglChooseConfig failed.\n"); goto error; } int var = eglGetConfigAttrib(g_egl_dpy, g_config, EGL_NATIVE_VISUAL_ID, &format); if (!var) { RARCH_ERR("eglGetConfigAttrib failed: %d.\n", var); goto error; } ANativeWindow_setBuffersGeometry(android_app->window, 0, 0, format); if (!(g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, android_app->window, 0))) { RARCH_ERR("eglCreateWindowSurface failed.\n"); goto error; } if (!(g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, 0, context_attributes))) { RARCH_ERR("eglCreateContext failed.\n"); goto error; } if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx)) { RARCH_ERR("eglMakeCurrent failed.\n"); goto error; } return true; error: RARCH_ERR("EGL error: %d.\n", eglGetError()); gfx_ctx_destroy(); return false; }
static bool gfx_ctx_init(void *data) { int i; unsigned monitor_index; unsigned gpu_index = 0; unsigned monitor = max(g_settings.video.monitor_index, 1); const char *gpu; if (g_inited) return false; g_drm_fd = -1; struct string_list *gpu_descriptors = dir_list_new("/dev/dri", NULL, false); nextgpu: free_drm_resources(); if (!gpu_descriptors || gpu_index == gpu_descriptors->size) { RARCH_ERR("[KMS/EGL]: Couldn't find a suitable DRM device.\n"); goto error; } gpu = gpu_descriptors->elems[gpu_index++].data; g_drm_fd = open(gpu, O_RDWR); if (g_drm_fd < 0) { RARCH_WARN("[KMS/EGL]: Couldn't open DRM device.\n"); goto nextgpu; } g_resources = drmModeGetResources(g_drm_fd); if (!g_resources) { RARCH_WARN("[KMS/EGL]: Couldn't get device resources.\n"); goto nextgpu; } // Enumerate all connectors. monitor_index = 0; RARCH_LOG("[KMS/EGL]: Found %d connectors.\n", g_resources->count_connectors); for (i = 0; i < g_resources->count_connectors; i++) { drmModeConnectorPtr conn = drmModeGetConnector(g_drm_fd, g_resources->connectors[i]); if (conn) { bool connected = conn->connection == DRM_MODE_CONNECTED; RARCH_LOG("[KMS/EGL]: Connector %d connected: %s\n", i, connected ? "yes" : "no"); RARCH_LOG("[KMS/EGL]: Connector %d has %d modes.\n", i, conn->count_modes); if (connected && conn->count_modes > 0) { monitor_index++; RARCH_LOG("[KMS/EGL]: Connector %d assigned to monitor index: #%u.\n", i, monitor_index); } drmModeFreeConnector(conn); } } monitor_index = 0; for (i = 0; i < g_resources->count_connectors; i++) { g_connector = drmModeGetConnector(g_drm_fd, g_resources->connectors[i]); if (!g_connector) continue; if (g_connector->connection == DRM_MODE_CONNECTED && g_connector->count_modes > 0) { monitor_index++; if (monitor_index == monitor) break; } drmModeFreeConnector(g_connector); g_connector = NULL; } if (!g_connector) { RARCH_WARN("[KMS/EGL]: Couldn't get device connector.\n"); goto nextgpu; } for (i = 0; i < g_resources->count_encoders; i++) { g_encoder = drmModeGetEncoder(g_drm_fd, g_resources->encoders[i]); if (!g_encoder) continue; if (g_encoder->encoder_id == g_connector->encoder_id) break; drmModeFreeEncoder(g_encoder); g_encoder = NULL; } if (!g_encoder) { RARCH_WARN("[KMS/EGL]: Couldn't find DRM encoder.\n"); goto nextgpu; } for (i = 0; i < g_connector->count_modes; i++) { RARCH_LOG("[KMS/EGL]: Mode %d: (%s) %d x %d, %u Hz\n", i, g_connector->modes[i].name, g_connector->modes[i].hdisplay, g_connector->modes[i].vdisplay, g_connector->modes[i].vrefresh); } g_crtc_id = g_encoder->crtc_id; g_orig_crtc = drmModeGetCrtc(g_drm_fd, g_crtc_id); if (!g_orig_crtc) RARCH_WARN("[KMS/EGL]: Cannot find original CRTC.\n"); g_connector_id = g_connector->connector_id; // First mode is assumed to be the "optimal" one for get_video_size() purposes. g_fb_width = g_connector->modes[0].hdisplay; g_fb_height = g_connector->modes[0].vdisplay; g_gbm_dev = gbm_create_device(g_drm_fd); if (!g_gbm_dev) { RARCH_WARN("[KMS/EGL]: Couldn't create GBM device.\n"); goto nextgpu; } dir_list_free(gpu_descriptors); return true; error: dir_list_free(gpu_descriptors); gfx_ctx_destroy(data); return false; }
static void *d3d_init(const video_info_t *info, const input_driver_t **input, void **input_data) { d3d_video_t *d3d = NULL; const gfx_ctx_driver_t *ctx_driver = NULL; #ifdef _XBOX if (video_driver_get_ptr(false)) { d3d = (d3d_video_t*)video_driver_get_ptr(false); /* Reinitialize renderchain as we * might have changed pixel formats.*/ if (d3d->renderchain_driver->reinit(d3d, (const void*)info)) { d3d_deinit_chain(d3d); d3d_init_chain(d3d, info); input_driver_set(input, input_data); video_driver_ctl(RARCH_DISPLAY_CTL_SET_OWN_DRIVER, NULL); return d3d; } } #endif d3d = new d3d_video_t(); if (!d3d) goto error; ctx_driver = d3d_get_context(d3d); if (!ctx_driver) goto error; /* Default values */ d3d->dev = NULL; d3d->dev_rotation = 0; d3d->needs_restore = false; #ifdef HAVE_OVERLAY d3d->overlays_enabled = false; #endif #ifdef _XBOX d3d->should_resize = false; #else #ifdef HAVE_MENU d3d->menu = NULL; #endif #endif gfx_ctx_set(ctx_driver); if (!d3d_construct(d3d, info, input, input_data)) { RARCH_ERR("[D3D]: Failed to init D3D.\n"); goto error; } d3d->keep_aspect = info->force_aspect; #ifdef _XBOX video_driver_ctl(RARCH_DISPLAY_CTL_SET_OWN_DRIVER, NULL); video_driver_ctl(RARCH_INPUT_CTL_SET_OWN_DRIVER, NULL); #endif return d3d; error: gfx_ctx_destroy(ctx_driver); if (d3d) delete d3d; return NULL; }
static bool gfx_ctx_init(void) { EGLint width; EGLint height; RARCH_LOG("[EMSCRIPTEN/EGL]: Initializing...\n"); if (g_inited) { RARCH_LOG("[EMSCRIPTEN/EGL]: Attempted to re-initialize driver.\n"); return true; } EGLint num_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 }; static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; // get an EGL display connection g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!g_egl_dpy) goto error; // initialize the EGL display connection if (!eglInitialize(g_egl_dpy, NULL, NULL)) goto error; // get an appropriate EGL frame buffer configuration if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_config, 1, &num_config)) goto error; // create an EGL rendering context g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, context_attributes); if (!g_egl_ctx) goto error; // create an EGL window surface g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, 0, 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; eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_WIDTH, &width); eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_HEIGHT, &height); g_fb_width = width; g_fb_height = height; RARCH_LOG("[EMSCRIPTEN/EGL]: Dimensions: %ux%u\n", width, height); return true; error: gfx_ctx_destroy(); return false; }