bool gl_init_hw_render(gl_t *gl, unsigned width, unsigned height) { GLenum status; unsigned i; bool depth = false; bool stencil = false; GLint max_fbo_size = 0; GLint max_renderbuffer_size = 0; struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); /* We can only share texture objects through contexts. * FBOs are "abstract" objects and are not shared. */ context_bind_hw_render(true); RARCH_LOG("[GL]: Initializing HW render (%u x %u).\n", width, height); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_fbo_size); glGetIntegerv(RARCH_GL_MAX_RENDERBUFFER_SIZE, &max_renderbuffer_size); RARCH_LOG("[GL]: Max texture size: %d px, renderbuffer size: %d px.\n", max_fbo_size, max_renderbuffer_size); if (!gl_check_capability(GL_CAPS_FBO)) return false; RARCH_LOG("[GL]: Supports FBO (render-to-texture).\n"); glBindTexture(GL_TEXTURE_2D, 0); glGenFramebuffers(gl->textures, gl->hw_render_fbo); depth = hwr->depth; stencil = hwr->stencil; #ifdef HAVE_OPENGLES if (!gl_check_capability(GL_CAPS_PACKED_DEPTH_STENCIL)) return false; RARCH_LOG("[GL]: Supports Packed depth stencil.\n"); #endif if (depth) { glGenRenderbuffers(gl->textures, gl->hw_render_depth); gl->hw_render_depth_init = true; } for (i = 0; i < gl->textures; i++) { glBindFramebuffer(RARCH_GL_FRAMEBUFFER, gl->hw_render_fbo[i]); glFramebufferTexture2D(RARCH_GL_FRAMEBUFFER, RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl->texture[i], 0); if (depth) { glBindRenderbuffer(RARCH_GL_RENDERBUFFER, gl->hw_render_depth[i]); glRenderbufferStorage(RARCH_GL_RENDERBUFFER, stencil ? RARCH_GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT16, width, height); glBindRenderbuffer(RARCH_GL_RENDERBUFFER, 0); if (stencil) { #if defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES1) || ((defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))) /* GLES2 is a bit weird, as always. * There's no GL_DEPTH_STENCIL_ATTACHMENT like in desktop GL. */ glFramebufferRenderbuffer(RARCH_GL_FRAMEBUFFER, RARCH_GL_DEPTH_ATTACHMENT, RARCH_GL_RENDERBUFFER, gl->hw_render_depth[i]); glFramebufferRenderbuffer(RARCH_GL_FRAMEBUFFER, RARCH_GL_STENCIL_ATTACHMENT, RARCH_GL_RENDERBUFFER, gl->hw_render_depth[i]); #else /* We use ARB FBO extensions, no need to check. */ glFramebufferRenderbuffer(RARCH_GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, RARCH_GL_RENDERBUFFER, gl->hw_render_depth[i]); #endif } else { glFramebufferRenderbuffer(RARCH_GL_FRAMEBUFFER, RARCH_GL_DEPTH_ATTACHMENT, RARCH_GL_RENDERBUFFER, gl->hw_render_depth[i]); } } status = glCheckFramebufferStatus(RARCH_GL_FRAMEBUFFER); if (status != RARCH_GL_FRAMEBUFFER_COMPLETE) { RARCH_ERR("[GL]: Failed to create HW render FBO #%u, error: 0x%u.\n", i, (unsigned)status); return false; } } gl_bind_backbuffer(); gl->hw_render_fbo_init = true; context_bind_hw_render(false); return true; }
static void *android_gfx_ctx_init(video_frame_info_t *video_info, void *video_driver) { #ifdef HAVE_OPENGLES EGLint n, major, minor; EGLint format; #if 0 struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); bool debug = hwr->debug_context; #endif EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, g_es3 ? 3 : 2, #if 0 EGL_CONTEXT_FLAGS_KHR, debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0, #endif EGL_NONE }; 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_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_NONE }; #endif struct android_app *android_app = (struct android_app*)g_android; android_ctx_data_t *and = (android_ctx_data_t*)calloc(1, sizeof(*and)); if (!android_app || !and) return false; #ifdef HAVE_OPENGLES if (g_es3) attribs[1] = EGL_OPENGL_ES3_BIT_KHR; #endif switch (android_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: #ifdef HAVE_EGL RARCH_LOG("Android EGL: GLES version = %d.\n", g_es3 ? 3 : 2); if (!egl_init_context(&and->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribs)) { egl_report_error(); goto error; } if (!egl_get_native_visual_id(&and->egl, &format)) goto error; #endif break; case GFX_CTX_VULKAN_API: #ifdef HAVE_VULKAN if (!vulkan_context_init(&and->vk, VULKAN_WSI_ANDROID)) goto error; #endif break; case GFX_CTX_NONE: default: break; } slock_lock(android_app->mutex); if (!android_app->window) goto unlock_error; switch (android_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: ANativeWindow_setBuffersGeometry(android_app->window, 0, 0, format); #ifdef HAVE_EGL if (!egl_create_context(&and->egl, context_attributes)) { egl_report_error(); goto unlock_error; } if (!egl_create_surface(&and->egl, android_app->window)) goto unlock_error; #endif break; case GFX_CTX_NONE: default: break; } slock_unlock(android_app->mutex); return and; unlock_error: slock_unlock(android_app->mutex); error: android_gfx_ctx_destroy(and); return NULL; }
static void create_gl_context(HWND hwnd, bool *quit) { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); bool debug = hwr->debug_context; bool core_context = (win32_major * 1000 + win32_minor) >= 3001; win32_hdc = GetDC(hwnd); setup_pixel_format(win32_hdc); #ifdef GL_DEBUG debug = true; #endif if (win32_hrc) { RARCH_LOG("[WGL]: Using cached GL context.\n"); video_driver_set_video_cache_context_ack(); } else { win32_hrc = wglCreateContext(win32_hdc); /* We'll create shared context later if not. */ if (win32_hrc && !core_context && !debug) { win32_hw_hrc = wglCreateContext(win32_hdc); if (win32_hw_hrc) { if (!wglShareLists(win32_hrc, win32_hw_hrc)) { RARCH_LOG("[WGL]: Failed to share contexts.\n"); *quit = true; } } else *quit = true; } } if (win32_hrc) { if (wglMakeCurrent(win32_hdc, win32_hrc)) g_win32_inited = true; else *quit = true; } else { *quit = true; return; } if (core_context || debug) { int attribs[16]; int *aptr = attribs; if (core_context) { *aptr++ = WGL_CONTEXT_MAJOR_VERSION_ARB; *aptr++ = win32_major; *aptr++ = WGL_CONTEXT_MINOR_VERSION_ARB; *aptr++ = win32_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 ((win32_major * 1000 + win32_minor) >= 3002) { *aptr++ = WGL_CONTEXT_PROFILE_MASK_ARB; *aptr++ = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; } } if (debug) { *aptr++ = WGL_CONTEXT_FLAGS_ARB; *aptr++ = WGL_CONTEXT_DEBUG_BIT_ARB; } *aptr = 0; if (!pcreate_context) pcreate_context = (wglCreateContextAttribsProc)gfx_ctx_wgl_get_proc_address("wglCreateContextAttribsARB"); if (pcreate_context) { HGLRC context = pcreate_context(win32_hdc, NULL, attribs); if (context) { wglMakeCurrent(NULL, NULL); wglDeleteContext(win32_hrc); win32_hrc = context; if (!wglMakeCurrent(win32_hdc, win32_hrc)) *quit = true; } else RARCH_ERR("[WGL]: Failed to create core context. Falling back to legacy context.\n"); if (win32_use_hw_ctx) { win32_hw_hrc = pcreate_context(win32_hdc, context, attribs); if (!win32_hw_hrc) { RARCH_ERR("[WGL]: Failed to create shared context.\n"); *quit = true; } } } else RARCH_ERR("[WGL]: wglCreateContextAttribsARB not supported.\n"); } { const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0; const char *extensions = NULL; wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC)) gfx_ctx_wgl_get_proc_address("wglGetExtensionsStringARB"); if (wglGetExtensionsStringARB) extensions = wglGetExtensionsStringARB(win32_hdc); RARCH_LOG("[WGL] extensions: %s\n", extensions); if (wgl_has_extension("WGL_EXT_swap_control_tear", extensions)) { RARCH_LOG("[WGL]: Adaptive VSync supported.\n"); wgl_adaptive_vsync = true; } } }
static EGLint *egl_fill_attribs(gfx_ctx_wayland_data_t *wl, EGLint *attr) { switch (wl_api) { #ifdef EGL_KHR_create_context case GFX_CTX_OPENGL_API: { bool debug = false; #ifdef HAVE_OPENGL unsigned version = wl->egl.major * 1000 + wl->egl.minor; bool core = version >= 3001; #ifndef GL_DEBUG struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); #endif #ifdef GL_DEBUG debug = true; #else debug = hwr->debug_context; #endif if (core) { *attr++ = EGL_CONTEXT_MAJOR_VERSION_KHR; *attr++ = wl->egl.major; *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; *attr++ = wl->egl.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 (version >= 3002) { *attr++ = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; *attr++ = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; } } if (debug) { *attr++ = EGL_CONTEXT_FLAGS_KHR; *attr++ = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; } #endif break; } #endif case GFX_CTX_OPENGL_ES_API: #ifdef HAVE_OPENGLES *attr++ = EGL_CONTEXT_CLIENT_VERSION; /* Same as EGL_CONTEXT_MAJOR_VERSION */ *attr++ = wl->egl.major ? (EGLint)wl->egl.major : 2; #ifdef EGL_KHR_create_context if (wl->egl.minor > 0) { *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; *attr++ = wl->egl.minor; } #endif #endif break; case GFX_CTX_NONE: default: break; } *attr = EGL_NONE; return attr; }
static void *gl1_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data) { unsigned full_x, full_y; gfx_ctx_input_t inp; gfx_ctx_mode_t mode; void *ctx_data = NULL; const gfx_ctx_driver_t *ctx_driver = NULL; unsigned win_width = 0, win_height = 0; unsigned temp_width = 0, temp_height = 0; settings_t *settings = config_get_ptr(); gl1_t *gl1 = (gl1_t*)calloc(1, sizeof(*gl1)); const char *vendor = NULL; const char *renderer = NULL; const char *version = NULL; const char *extensions = NULL; int interval = 0; struct retro_hw_render_callback *hwr = NULL; if (!gl1) return NULL; *input = NULL; *input_data = NULL; gl1_video_width = video->width; gl1_video_height = video->height; gl1_rgb32 = video->rgb32; gl1_video_bits = video->rgb32 ? 32 : 16; if (video->rgb32) gl1_video_pitch = video->width * 4; else gl1_video_pitch = video->width * 2; ctx_driver = video_context_driver_init_first(gl1, settings->arrays.video_context_driver, GFX_CTX_OPENGL_API, 1, 1, false, &ctx_data); if (!ctx_driver) goto error; if (ctx_data) gl1->ctx_data = ctx_data; gl1->ctx_driver = ctx_driver; video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver); RARCH_LOG("[GL1]: Found GL1 context: %s\n", ctx_driver->ident); video_context_driver_get_video_size(&mode); full_x = mode.width; full_y = mode.height; mode.width = 0; mode.height = 0; /* Clear out potential error flags in case we use cached context. */ glGetError(); if (string_is_equal(ctx_driver->ident, "null")) goto error; RARCH_LOG("[GL1]: Detecting screen resolution %ux%u.\n", full_x, full_y); win_width = video->width; win_height = video->height; if (video->fullscreen && (win_width == 0) && (win_height == 0)) { win_width = full_x; win_height = full_y; } mode.width = win_width; mode.height = win_height; mode.fullscreen = video->fullscreen; interval = video->swap_interval; video_context_driver_swap_interval(&interval); if (!video_context_driver_set_video_mode(&mode)) goto error; gl1->fullscreen = video->fullscreen; mode.width = 0; mode.height = 0; video_context_driver_get_video_size(&mode); temp_width = mode.width; temp_height = mode.height; mode.width = 0; mode.height = 0; /* Get real known video size, which might have been altered by context. */ if (temp_width != 0 && temp_height != 0) video_driver_set_size(&temp_width, &temp_height); video_driver_get_size(&temp_width, &temp_height); RARCH_LOG("[GL1]: Using resolution %ux%u\n", temp_width, temp_height); vendor = (const char*)glGetString(GL_VENDOR); renderer = (const char*)glGetString(GL_RENDERER); version = (const char*)glGetString(GL_VERSION); extensions = (const char*)glGetString(GL_EXTENSIONS); if (!string_is_empty(version)) sscanf(version, "%d.%d", &gl1->version_major, &gl1->version_minor); if (!string_is_empty(extensions)) gl1->extensions = string_split(extensions, " "); RARCH_LOG("[GL1]: Vendor: %s, Renderer: %s.\n", vendor, renderer); RARCH_LOG("[GL1]: Version: %s.\n", version); RARCH_LOG("[GL1]: Extensions: %s\n", extensions); { char device_str[128]; device_str[0] = '\0'; if (!string_is_empty(vendor)) { strlcpy(device_str, vendor, sizeof(device_str)); strlcat(device_str, " ", sizeof(device_str)); } if (!string_is_empty(renderer)) strlcat(device_str, renderer, sizeof(device_str)); video_driver_set_gpu_device_string(device_str); if (!string_is_empty(version)) video_driver_set_gpu_api_version_string(version); } inp.input = input; inp.input_data = input_data; video_context_driver_input_driver(&inp); if (settings->bools.video_font_enable) font_driver_init_osd(gl1, false, video->is_threaded, FONT_DRIVER_RENDER_OPENGL1_API); gl1->smooth = settings->bools.video_smooth; gl1->supports_bgra = string_list_find_elem(gl1->extensions, "GL_EXT_bgra"); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_STENCIL_TEST); glDisable(GL_SCISSOR_TEST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &gl1->tex); glGenTextures(1, &gl1->menu_tex); hwr = video_driver_get_hw_context(); memcpy(gl1->tex_info.coord, gl1_tex_coords, sizeof(gl1->tex_info.coord)); gl1->vertex_ptr = hwr->bottom_left_origin ? gl1_vertexes : gl1_vertexes_flipped; gl1->textures = 4; gl1->white_color_ptr = gl1_white_color; gl1->coords.vertex = gl1->vertex_ptr; gl1->coords.tex_coord = gl1->tex_info.coord; gl1->coords.color = gl1->white_color_ptr; gl1->coords.lut_tex_coord = gl1_tex_coords; gl1->coords.vertices = 4; RARCH_LOG("[GL1]: Init complete.\n"); return gl1; error: video_context_driver_destroy(); if (gl1) { if (gl1->extensions) string_list_free(gl1->extensions); free(gl1); } return NULL; }
/** * drivers_init: * @flags : Bitmask of drivers to initialize. * * Initializes drivers. * @flags determines which drivers get initialized. **/ void drivers_init(int flags) { bool video_is_threaded = false; if (flags & DRIVER_VIDEO_MASK) video_driver_unset_own_driver(); if (flags & DRIVER_AUDIO_MASK) audio_driver_unset_own_driver(); if (flags & DRIVER_INPUT_MASK) input_driver_unset_own_driver(); if (flags & DRIVER_CAMERA_MASK) camera_driver_ctl(RARCH_CAMERA_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_LOCATION_MASK) location_driver_ctl(RARCH_LOCATION_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_WIFI_MASK) wifi_driver_ctl(RARCH_WIFI_CTL_UNSET_OWN_DRIVER, NULL); #ifdef HAVE_MENU /* By default, we want the menu to persist through driver reinits. */ menu_driver_ctl(RARCH_MENU_CTL_SET_OWN_DRIVER, NULL); #endif if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK)) driver_adjust_system_rates(); if (flags & DRIVER_VIDEO_MASK) { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); video_driver_monitor_reset(); video_driver_init(&video_is_threaded); if (!video_driver_is_video_cache_context_ack() && hwr->context_reset) hwr->context_reset(); video_driver_unset_video_cache_context_ack(); rarch_ctl(RARCH_CTL_SET_FRAME_TIME_LAST, NULL); } if (flags & DRIVER_AUDIO_MASK) { audio_driver_init(); audio_driver_new_devices_list(); } /* Only initialize camera driver if we're ever going to use it. */ if ((flags & DRIVER_CAMERA_MASK) && camera_driver_ctl(RARCH_CAMERA_CTL_IS_ACTIVE, NULL)) camera_driver_ctl(RARCH_CAMERA_CTL_INIT, NULL); /* Only initialize location driver if we're ever going to use it. */ if ((flags & DRIVER_LOCATION_MASK) && location_driver_ctl(RARCH_LOCATION_CTL_IS_ACTIVE, NULL)) init_location(); core_info_init_current_core(); #ifdef HAVE_MENU if (flags & DRIVER_VIDEO_MASK) { if (flags & DRIVER_MENU_MASK) menu_driver_init(video_is_threaded); } #endif if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK)) { /* Keep non-throttled state as good as possible. */ if (input_driver_is_nonblock_state()) driver_set_nonblock_state(); } if (flags & DRIVER_LED_MASK) { led_driver_init(); } if (flags & DRIVER_MIDI_MASK) midi_driver_init(); }
static bool gl_raster_font_upload_atlas(gl_raster_t *font) { unsigned i, j; GLint gl_internal = GL_LUMINANCE_ALPHA; GLenum gl_format = GL_LUMINANCE_ALPHA; size_t ncomponents = 2; uint8_t *tmp = NULL; #if 0 bool ancient = false; /* add a check here if needed */ #endif #if defined(GL_VERSION_3_0) struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); #endif #if 0 if (ancient) { gl_internal = GL_RGBA; gl_format = GL_RGBA; ncomponents = 4; } #endif #if defined(GL_VERSION_3_0) if (gl_query_core_context_in_use() || (hwr->context_type == RETRO_HW_CONTEXT_OPENGL && hwr->version_major >= 3)) { GLint swizzle[] = { GL_ONE, GL_ONE, GL_ONE, GL_RED }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle); gl_internal = GL_R8; gl_format = GL_RED; ncomponents = 1; } #endif tmp = (uint8_t*)calloc(font->tex_height, font->tex_width * ncomponents); if (!tmp) return false; for (i = 0; i < font->atlas->height; ++i) { const uint8_t *src = &font->atlas->buffer[i * font->atlas->width]; uint8_t *dst = &tmp[i * font->tex_width * ncomponents]; switch (ncomponents) { case 1: memcpy(dst, src, font->atlas->width); break; case 2: for (j = 0; j < font->atlas->width; ++j) { *dst++ = 0xff; *dst++ = *src++; } break; case 4: for (j = 0; j < font->atlas->width; ++j) { *dst++ = 0xff; *dst++ = 0xff; *dst++ = 0xff; *dst++ = *src++; } break; default: RARCH_ERR("Unsupported number of components: %u\n", (unsigned)ncomponents); free(tmp); return false; } } glTexImage2D(GL_TEXTURE_2D, 0, gl_internal, font->tex_width, font->tex_height, 0, gl_format, GL_UNSIGNED_BYTE, tmp); free(tmp); return true; }
/** * init_drivers: * @flags : Bitmask of drivers to initialize. * * Initializes drivers. * @flags determines which drivers get initialized. **/ static void init_drivers(int flags) { if (flags & DRIVER_VIDEO) video_driver_unset_own_driver(); if (flags & DRIVER_AUDIO) audio_driver_unset_own_driver(); if (flags & DRIVER_INPUT) input_driver_unset_own_driver(); if (flags & DRIVER_CAMERA) camera_driver_ctl(RARCH_CAMERA_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_LOCATION) location_driver_ctl(RARCH_LOCATION_CTL_UNSET_OWN_DRIVER, NULL); #ifdef HAVE_MENU /* By default, we want the menu to persist through driver reinits. */ menu_driver_ctl(RARCH_MENU_CTL_SET_OWN_DRIVER, NULL); #endif if (flags & (DRIVER_VIDEO | DRIVER_AUDIO)) driver_adjust_system_rates(); if (flags & DRIVER_VIDEO) { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); video_driver_monitor_reset(); video_driver_init(); if (!video_driver_is_video_cache_context_ack() && hwr->context_reset) hwr->context_reset(); video_driver_unset_video_cache_context_ack(); runloop_ctl(RUNLOOP_CTL_SET_FRAME_TIME_LAST, NULL); } if (flags & DRIVER_AUDIO) { audio_driver_init(); audio_driver_new_devices_list(); } /* Only initialize camera driver if we're ever going to use it. */ if ((flags & DRIVER_CAMERA) && camera_driver_ctl(RARCH_CAMERA_CTL_IS_ACTIVE, NULL)) camera_driver_ctl(RARCH_CAMERA_CTL_INIT, NULL); /* Only initialize location driver if we're ever going to use it. */ if ((flags & DRIVER_LOCATION) && location_driver_ctl(RARCH_LOCATION_CTL_IS_ACTIVE, NULL)) init_location(); #ifdef HAVE_MENU if (flags & DRIVER_MENU) { menu_driver_ctl(RARCH_MENU_CTL_INIT, NULL); menu_driver_ctl(RARCH_MENU_CTL_CONTEXT_RESET, NULL); } #endif if (flags & (DRIVER_VIDEO | DRIVER_AUDIO)) { /* Keep non-throttled state as good as possible. */ if (input_driver_is_nonblock_state()) driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); } }
bool gl_check_capability(enum gl_capability_enum enum_idx) { unsigned major = 0; unsigned minor = 0; const char *vendor = (const char*)glGetString(GL_VENDOR); const char *renderer = (const char*)glGetString(GL_RENDERER); const char *version = (const char*)glGetString(GL_VERSION); #ifdef HAVE_OPENGLES if (version && sscanf(version, "OpenGL ES %u.%u", &major, &minor) != 2) #else if (version && sscanf(version, "%u.%u", &major, &minor) != 2) #endif major = minor = 0; (void)vendor; switch (enum_idx) { case GL_CAPS_GLES3_SUPPORTED: #if defined(HAVE_OPENGLES) if (major >= 3) return true; #endif break; case GL_CAPS_EGLIMAGE: #if defined(HAVE_EGL) && defined(HAVE_OPENGLES) if (glEGLImageTargetTexture2DOES != NULL) return true; #endif break; case GL_CAPS_SYNC: #ifdef HAVE_OPENGLES if (major >= 3) return true; #else if (gl_query_extension("ARB_sync") && glFenceSync && glDeleteSync && glClientWaitSync) return true; #endif break; case GL_CAPS_MIPMAP: { static bool extension_queried = false; static bool extension = false; if (!extension_queried) { extension = gl_query_extension("ARB_framebuffer_object"); extension_queried = true; } if (extension) return true; } break; case GL_CAPS_VAO: #ifndef HAVE_OPENGLES if (!gl_query_core_context_in_use() && !gl_query_extension("ARB_vertex_array_object")) return false; if (glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays) return true; #endif break; case GL_CAPS_FBO: #if defined(HAVE_PSGL) || defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2) return true; #elif defined(HAVE_FBO) if (!gl_query_core_context_in_use() && !gl_query_extension("ARB_framebuffer_object") && !gl_query_extension("EXT_framebuffer_object")) return false; if (glGenFramebuffers && glBindFramebuffer && glFramebufferTexture2D && glCheckFramebufferStatus && glDeleteFramebuffers && glGenRenderbuffers && glBindRenderbuffer && glFramebufferRenderbuffer && glRenderbufferStorage && glDeleteRenderbuffers) return true; break; #else break; #endif case GL_CAPS_ARGB8: #ifdef HAVE_OPENGLES if (gl_query_extension("OES_rgb8_rgba8") || gl_query_extension("ARM_argb8")) return true; #else /* TODO/FIXME - implement this for non-GLES? */ #endif break; case GL_CAPS_DEBUG: if (gl_query_extension("KHR_debug")) return true; #ifndef HAVE_OPENGLES if (gl_query_extension("ARB_debug_output")) return true; #endif break; case GL_CAPS_PACKED_DEPTH_STENCIL: { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); if (major >= 3) return true; if (hwr->stencil && !gl_query_extension("OES_packed_depth_stencil") && !gl_query_extension("EXT_packed_depth_stencil")) return false; } return true; case GL_CAPS_ES2_COMPAT: #ifndef HAVE_OPENGLES /* ATI card detected, skipping check for GL_RGB565 support... */ if (vendor && renderer && (strstr(vendor, "ATI") || strstr(renderer, "ATI"))) return false; if (gl_query_extension("ARB_ES2_compatibility")) return true; #endif break; case GL_CAPS_UNPACK_ROW_LENGTH: #ifdef HAVE_OPENGLES if (major >= 3) return true; /* Extension GL_EXT_unpack_subimage, can copy textures faster * than using UNPACK_ROW_LENGTH */ if (gl_query_extension("GL_EXT_unpack_subimage")) return true; #endif break; case GL_CAPS_FULL_NPOT_SUPPORT: if (major >= 3) return true; #ifdef HAVE_OPENGLES if (gl_query_extension("ARB_texture_non_power_of_two") || gl_query_extension("OES_texture_npot")) return true; #else { GLint max_texture_size = 0; GLint max_native_instr = 0; /* try to detect actual npot support. might fail for older cards. */ bool arb_npot = gl_query_extension("ARB_texture_non_power_of_two"); bool arb_frag_program = gl_query_extension("ARB_fragment_program"); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); #ifdef GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB if (arb_frag_program && glGetProgramivARB) glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &max_native_instr); #endif if (arb_npot && arb_frag_program && (max_texture_size >= 8192) && (max_native_instr >= 4096)) return true; } #endif break; case GL_CAPS_SRGB_FBO_ES3: #ifdef HAVE_OPENGLES if (major >= 3) return true; #else break; #endif case GL_CAPS_SRGB_FBO: #if defined(HAVE_OPENGLES) if (major >= 3 || gl_query_extension("EXT_sRGB")) return true; #elif defined(HAVE_FBO) if (gl_query_core_context_in_use() || (gl_query_extension("EXT_texture_sRGB") && gl_query_extension("ARB_framebuffer_sRGB"))) return true; #endif break; case GL_CAPS_FP_FBO: /* GLES - No extensions for float FBO currently. */ #ifndef HAVE_OPENGLES #ifdef HAVE_FBO /* Float FBO is core in 3.2. */ if (gl_query_core_context_in_use() || gl_query_extension("ARB_texture_float")) return true; #endif #endif break; case GL_CAPS_BGRA8888: #ifdef HAVE_OPENGLES /* There are both APPLE and EXT variants. */ /* Videocore hardware supports BGRA8888 extension, but * should be purposefully avoided. */ if (gl_query_extension("BGRA8888") && !strstr(renderer, "VideoCore")) return true; #else /* TODO/FIXME - implement this for non-GLES? */ #endif break; case GL_CAPS_NONE: default: break; } return false; }
enum rarch_shader_type video_shader_get_type_from_ext( const char *ext, bool *is_preset) { enum gfx_ctx_api api = video_context_driver_get_api(); if (string_is_empty(ext)) return RARCH_SHADER_NONE; if (strlen(ext) > 1 && ext[0] == '.') ext++; *is_preset = false; if ( string_is_equal_case_insensitive(ext, "cg") ) { switch (api) { case GFX_CTX_DIRECT3D9_API: return RARCH_SHADER_CG; case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); if (hwr) { switch (hwr->context_type) { case RETRO_HW_CONTEXT_OPENGLES2: case RETRO_HW_CONTEXT_OPENGL_CORE: case RETRO_HW_CONTEXT_OPENGLES3: return RARCH_SHADER_NONE; default: break; } } } return RARCH_SHADER_CG; default: break; } } if ( string_is_equal_case_insensitive(ext, "cgp") ) { *is_preset = true; switch (api) { case GFX_CTX_DIRECT3D9_API: return RARCH_SHADER_CG; case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); if (hwr) { switch (hwr->context_type) { case RETRO_HW_CONTEXT_OPENGLES2: case RETRO_HW_CONTEXT_OPENGL_CORE: case RETRO_HW_CONTEXT_OPENGLES3: return RARCH_SHADER_NONE; default: break; } } } return RARCH_SHADER_CG; default: break; } } if ( string_is_equal_case_insensitive(ext, "glsl") ) { switch (api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: return RARCH_SHADER_GLSL; default: break; } } if ( string_is_equal_case_insensitive(ext, "glslp") ) { *is_preset = true; switch (api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: return RARCH_SHADER_GLSL; default: break; } } if ( string_is_equal_case_insensitive(ext, "slang") ) { switch (api) { case GFX_CTX_DIRECT3D10_API: case GFX_CTX_DIRECT3D11_API: case GFX_CTX_DIRECT3D12_API: case GFX_CTX_GX2_API: case GFX_CTX_VULKAN_API: case GFX_CTX_METAL_API: return RARCH_SHADER_SLANG; default: break; } } if ( string_is_equal_case_insensitive(ext, "slangp") ) { *is_preset = true; switch (api) { case GFX_CTX_DIRECT3D10_API: case GFX_CTX_DIRECT3D11_API: case GFX_CTX_DIRECT3D12_API: case GFX_CTX_GX2_API: case GFX_CTX_VULKAN_API: case GFX_CTX_METAL_API: return RARCH_SHADER_SLANG; default: break; } } return RARCH_SHADER_NONE; }
static void *gfx_ctx_x_init(video_frame_info_t *video_info, void *data) { int nelements = 0; int major = 0; int minor = 0; #ifdef HAVE_OPENGL 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, GLX_SAMPLE_BUFFERS , 0, GLX_SAMPLES , 0, None }; GLXFBConfig *fbcs = NULL; #endif gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*) calloc(1, sizeof(gfx_ctx_x_data_t)); #ifndef GL_DEBUG struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); #endif if (!x) return NULL; current_context_data = x; XInitThreads(); if (!x11_connect()) goto error; switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) glXQueryVersion(g_x11_dpy, &major, &minor); /* GLX 1.3+ minimum required. */ if ((major * 1000 + minor) < 1003) goto error; glx_create_context_attribs = (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); #ifdef GL_DEBUG x->g_debug = true; #else x->g_debug = hwr->debug_context; #endif /* Have to use ContextAttribs */ #ifdef HAVE_OPENGLES2 x->g_core_es = true; x->g_core_es_core = true; #else x->g_core_es = (g_major * 1000 + g_minor) >= 3001; x->g_core_es_core = (g_major * 1000 + g_minor) >= 3002; #endif if ((x->g_core_es || x->g_debug) && !glx_create_context_attribs) goto error; fbcs = glXChooseFBConfig(g_x11_dpy, DefaultScreen(g_x11_dpy), visual_attribs, &nelements); if (!fbcs) goto error; if (!nelements) { XFree(fbcs); goto error; } x->g_fbc = fbcs[0]; XFree(fbcs); #endif break; case GFX_CTX_VULKAN_API: #ifdef HAVE_VULKAN /* Use XCB WSI since it's the most supported WSI over legacy Xlib. */ if (!vulkan_context_init(&x->vk, VULKAN_WSI_XCB)) goto error; #endif break; case GFX_CTX_NONE: default: break; } switch (x_api) { case GFX_CTX_OPENGL_API: #ifdef HAVE_OPENGL if (GLXExtensionSupported(g_x11_dpy, "GLX_EXT_swap_control_tear")) { RARCH_LOG("[GLX]: GLX_EXT_swap_control_tear supported.\n"); x_adaptive_vsync = true; } if (GLXExtensionSupported(g_x11_dpy, "GLX_OML_sync_control") && GLXExtensionSupported(g_x11_dpy, "GLX_MESA_swap_control") ) { RARCH_LOG("[GLX]: GLX_OML_sync_control and GLX_MESA_swap_control supported, using better swap control method...\n"); x->swap_mode = 1; glXGetSyncValuesOML = (GLXGETSYNCVALUESOMLPROC)glXGetProcAddress((unsigned char *)"glXGetSyncValuesOML"); glXGetMscRateOML = (GLXGETMSCRATEOMLPROC)glXGetProcAddress((unsigned char *)"glXGetMscRateOML"); glXSwapBuffersMscOML = (GLXSWAPBUFFERSMSCOMLPROC)glXGetProcAddress((unsigned char *)"glXSwapBuffersMscOML"); glXWaitForMscOML = (GLXWAITFORMSCOMLPROC)glXGetProcAddress((unsigned char *)"glXWaitForMscOML"); glXWaitForSbcOML = (GLXWAITFORSBCOMLPROC)glXGetProcAddress((unsigned char *)"glXWaitForSbcOML"); glXGetSyncValuesOML(g_x11_dpy, g_x11_win, &x->ust, &x->msc, &x->sbc); #if 0 RARCH_LOG("[GLX]: UST: %d, MSC: %d, SBC: %d\n", x->ust, x->msc, x->sbc); #endif } #endif break; default: break; } return x; error: if (x) { gfx_ctx_x_destroy_resources(x); free(x); } g_x11_screen = 0; return NULL; }