1
0
mirror of https://github.com/libretro/RetroArch synced 2025-03-28 08:37:41 +00:00

Add experimental X/EGL support.

This commit is contained in:
Themaister 2012-09-15 15:17:34 +02:00
parent d3b1780a66
commit ff60bcb5e5
12 changed files with 586 additions and 77 deletions

@ -124,7 +124,7 @@ ifeq ($(HAVE_COREAUDIO), 1)
endif
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/sdl_gfx.o gfx/context/sdl_ctx.o input/sdl_input.o audio/sdl_audio.o fifo_buffer.o
OBJ += gfx/sdl_gfx.o input/sdl_input.o audio/sdl_audio.o fifo_buffer.o
OBJ += gfx/scaler/scaler.o gfx/scaler/pixconv.o gfx/scaler/scaler_int.o gfx/scaler/filter.o
DEFINES += $(SDL_CFLAGS) $(BSD_LOCAL_INC)
LIBS += $(SDL_LIBS)
@ -143,10 +143,18 @@ endif
ifeq ($(HAVE_OPENGL), 1)
OBJ += gfx/gl.o gfx/fonts/freetype.o gfx/math/matrix.o
ifeq ($(OSX),1)
LIBS += -framework OpenGL
else
ifeq ($(HAVE_GLES), 1)
LIBS += -lGL -lGLESv2 -lEGL
DEFINES += -DHAVE_OPENGLES -DHAVE_OPENGLES2
OBJ += gfx/context/xegl_ctx.o
else
LIBS += -lGL
OBJ += gfx/context/sdl_ctx.o
endif
endif
endif
endif

@ -185,16 +185,6 @@ void gfx_ctx_swap_buffers(void)
SDL_GL_SwapBuffers();
}
bool gfx_ctx_key_pressed(int key)
{
int num_keys;
Uint8 *keymap = SDL_GetKeyState(&num_keys);
if (key >= num_keys)
return false;
return keymap[key];
}
// 1.2 specific workaround for tiling WMs. In 1.3 we call GetSize directly, so we don't need to rely on
// proper event handling (I hope).
#if !defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_X11)

400
gfx/context/xegl_ctx.c Normal file

@ -0,0 +1,400 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
* Copyright (C) 2011-2012 - Daniel De Matteis
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
// X/EGL context. Mostly used for testing GLES code paths.
// Should be its own file as it has lots of X11 stuff baked into it as well.
#include "../../driver.h"
#include "../gfx_context.h"
#include "../gl_common.h"
#include "../gfx_common.h"
#include <signal.h>
#include <stdint.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
static Display *g_dpy;
static Window g_win;
static Colormap g_cmap;
static Atom g_quit_atom;
static bool g_has_focus;
static EGLContext g_egl_ctx;
static EGLSurface g_egl_surf;
static EGLDisplay g_egl_dpy;
static EGLConfig g_config;
static volatile sig_atomic_t g_quit;
static bool g_inited;
static unsigned g_interval;
static void sighandler(int sig)
{
(void)sig;
g_quit = 1;
}
static void hide_mouse(void)
{
Cursor no_ptr;
Pixmap bm_no;
XColor black, dummy;
Colormap colormap;
static char bm_no_data[] = {0, 0, 0, 0, 0, 0, 0, 0};
colormap = DefaultColormap(g_dpy, DefaultScreen(g_dpy));
if (!XAllocNamedColor(g_dpy, colormap, "black", &black, &dummy))
return;
bm_no = XCreateBitmapFromData(g_dpy, g_win, bm_no_data, 8, 8);
no_ptr = XCreatePixmapCursor(g_dpy, bm_no, bm_no, &black, &black, 0, 0);
XDefineCursor(g_dpy, g_win, no_ptr);
XFreeCursor(g_dpy, no_ptr);
if (bm_no != None)
XFreePixmap(g_dpy, bm_no);
XFreeColors(g_dpy, colormap, &black.pixel, 1, 0);
}
static Atom XA_NET_WM_STATE;
static Atom XA_NET_WM_STATE_FULLSCREEN;
#define XA_INIT(x) XA##x = XInternAtom(g_dpy, #x, False)
#define _NET_WM_STATE_ADD 1
static void set_windowed_fullscreen(void)
{
XA_INIT(_NET_WM_STATE);
XA_INIT(_NET_WM_STATE_FULLSCREEN);
if (!XA_NET_WM_STATE || !XA_NET_WM_STATE_FULLSCREEN)
{
RARCH_ERR("[X/EGL]: Cannot set windowed fullscreen.\n");
return;
}
XEvent xev;
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
xev.xclient.send_event = True;
xev.xclient.message_type = XA_NET_WM_STATE;
xev.xclient.window = g_win;
xev.xclient.format = 32;
xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
xev.xclient.data.l[1] = XA_NET_WM_STATE_FULLSCREEN;
xev.xclient.data.l[2] = 0;
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = 0;
XSendEvent(g_dpy, DefaultRootWindow(g_dpy), False,
SubstructureRedirectMask | SubstructureNotifyMask,
&xev);
}
void gfx_ctx_set_swap_interval(unsigned interval, bool inited)
{
g_interval = interval;
if (inited)
eglSwapInterval(g_egl_dpy, g_interval);
}
void gfx_ctx_check_window(bool *quit,
bool *resize, unsigned *width, unsigned *height, unsigned frame_count)
{
(void)frame_count;
unsigned new_width = *width, new_height = *height;
gfx_ctx_get_video_size(&new_width, &new_height);
if (new_width != *width || new_height != *height)
{
*resize = true;
*width = new_width;
*height = new_height;
}
XEvent event;
while (XPending(g_dpy))
{
XNextEvent(g_dpy, &event);
switch (event.type)
{
case ClientMessage:
if ((Atom)event.xclient.data.l[0] == g_quit_atom)
g_quit = true;
break;
case DestroyNotify:
g_quit = true;
break;
case MapNotify:
g_has_focus = false;
break;
case UnmapNotify:
g_has_focus = false;
break;
}
}
*quit = g_quit;
}
void gfx_ctx_swap_buffers(void)
{
eglSwapBuffers(g_egl_dpy, g_egl_surf);
}
void gfx_ctx_set_resize(unsigned width, unsigned height)
{
(void)width;
(void)height;
}
void gfx_ctx_update_window_title(bool reset)
{
if (reset)
gfx_window_title_reset();
char buf[128];
if (gfx_window_title(buf, sizeof(buf)))
XStoreName(g_dpy, g_win, buf);
}
void gfx_ctx_get_video_size(unsigned *width, unsigned *height)
{
if (!g_dpy || g_win == None)
{
*width = 0;
*height = 0;
}
else
{
XWindowAttributes target;
XGetWindowAttributes(g_dpy, g_win, &target);
*width = target.width;
*height = target.height;
}
}
bool gfx_ctx_init(void)
{
if (g_inited)
return false;
g_quit = 0;
g_dpy = XOpenDisplay(NULL);
if (!g_dpy)
goto error;
g_egl_dpy = eglGetDisplay(g_dpy);
if (!g_egl_dpy)
goto error;
EGLint egl_major, egl_minor;
if (!eglInitialize(g_egl_dpy, &egl_major, &egl_minor))
goto error;
RARCH_LOG("[X/EGL]: EGL version: %d.%d\n", egl_major, egl_minor);
const EGLint egl_attribs[] = {
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_DEPTH_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE,
};
EGLint num_configs;
if (!eglChooseConfig(g_egl_dpy, egl_attribs, &g_config, 1, &num_configs)
|| num_configs == 0 || !g_config)
goto error;
return true;
error:
gfx_ctx_destroy();
return false;
}
bool gfx_ctx_set_video_mode(
unsigned width, unsigned height,
unsigned bits, bool fullscreen)
{
(void)bits;
const EGLint egl_ctx_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE,
};
XVisualInfo *vi = NULL;
EGLint vid;
if (!eglGetConfigAttrib(g_egl_dpy, g_config, EGL_NATIVE_VISUAL_ID, &vid))
goto error;
XVisualInfo template = {0};
template.visualid = vid;
EGLint num_visuals;
vi = XGetVisualInfo(g_dpy, VisualIDMask, &template, &num_visuals);
if (!vi)
goto error;
XSetWindowAttributes swa = {0};
swa.colormap = g_cmap = XCreateColormap(g_dpy, RootWindow(g_dpy, vi->screen),
vi->visual, AllocNone);
swa.event_mask = StructureNotifyMask;
g_win = XCreateWindow(g_dpy, RootWindow(g_dpy, vi->screen),
0, 0, width ? width : 200, height ? height : 200, 0,
vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask, &swa);
XSetWindowBackground(g_dpy, g_win, 0);
eglBindAPI(EGL_OPENGL_ES2_BIT);
g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, egl_ctx_attribs);
if (!g_egl_ctx)
goto error;
g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, 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;
gfx_ctx_update_window_title(true);
hide_mouse();
XMapWindow(g_dpy, g_win);
if (fullscreen)
set_windowed_fullscreen();
g_quit_atom = XInternAtom(g_dpy, "WM_DELETE_WINDOW", False);
if (g_quit_atom)
XSetWMProtocols(g_dpy, g_win, &g_quit_atom, 1);
// Catch signals.
struct sigaction sa = {
.sa_handler = sighandler,
.sa_flags = SA_RESTART,
};
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
XFree(vi);
g_has_focus = true;
g_inited = true;
return true;
error:
if (vi)
XFree(vi);
gfx_ctx_destroy();
return false;
}
void gfx_ctx_destroy(void)
{
if (g_egl_dpy)
{
if (g_egl_ctx)
eglDestroyContext(g_egl_dpy, g_egl_ctx);
if (g_egl_surf)
eglDestroySurface(g_egl_dpy, g_egl_surf);
eglTerminate(g_egl_dpy);
}
g_egl_ctx = NULL;
g_egl_surf = NULL;
g_egl_dpy = NULL;
if (g_win)
{
XDestroyWindow(g_dpy, g_win);
g_win = None;
}
if (g_cmap)
{
XFreeColormap(g_dpy, g_cmap);
g_cmap = None;
}
if (g_dpy)
{
XCloseDisplay(g_dpy);
g_dpy = NULL;
}
g_inited = false;
}
void gfx_ctx_input_driver(const input_driver_t **input, void **input_data)
{
void *xinput = input_x.init();
*input = xinput ? &input_x : NULL;
*input_data = xinput;
}
void gfx_ctx_set_projection(gl_t *gl, const struct gl_ortho *ortho, bool allow_rotate)
{
// Calculate projection.
math_matrix proj;
matrix_ortho(&proj, ortho->left, ortho->right,
ortho->bottom, ortho->top, ortho->znear, ortho->zfar);
if (allow_rotate)
{
math_matrix rot;
matrix_rotate_z(&rot, M_PI * gl->rotation / 180.0f);
matrix_multiply(&proj, &rot, &proj);
}
gl->mvp = proj;
}
bool gfx_ctx_window_has_focus(void)
{
if (!g_inited)
return false;
Window win;
int rev;
XGetInputFocus(g_dpy, &win, &rev);
return win == g_win && g_has_focus;
}
// Enforce void (*)(void) as it's not really legal to cast void* to fn-pointer.
// POSIX allows this, but strict C99 doesn't.
gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol)
{
return eglGetProcAddress(symbol);
}

@ -33,8 +33,8 @@ void gl_init_font(gl_t *gl, const char *font_path, unsigned font_size)
{
glGenTextures(1, &gl->font_tex);
glBindTexture(GL_TEXTURE_2D, gl->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
@ -127,6 +127,12 @@ static void calculate_msg_geometry(const struct font_output *head, struct font_r
rect->height = y_max - y_min;
}
#ifdef HAVE_OPENGLES2
#define INTENSITY_FORMAT GL_LUMINANCE
#else
#define INTENSITY_FORMAT GL_INTENSITY8
#endif
static void adjust_power_of_two(gl_t *gl, struct font_rect *geom)
{
// Some systems really hate NPOT textures.
@ -139,15 +145,12 @@ static void adjust_power_of_two(gl_t *gl, struct font_rect *geom)
memset(gl->font_tex_empty_buf, 0, geom->pot_width * geom->pot_height);
glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
glPixelStorei(GL_UNPACK_ROW_LENGTH, geom->pot_width);
glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY8, geom->pot_width, geom->pot_height,
glTexImage2D(GL_TEXTURE_2D, 0, INTENSITY_FORMAT, geom->pot_width, geom->pot_height,
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, gl->font_tex_empty_buf);
gl->font_tex_w = geom->pot_width;
gl->font_tex_h = geom->pot_height;
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
// Old style "blitting", so we can render all the fonts in one go.
@ -156,7 +159,6 @@ static void blit_fonts(gl_t *gl, const struct font_output *head, const struct fo
{
// Clear out earlier fonts.
glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, gl->font_tex_w, gl->font_tex_h,
GL_LUMINANCE, GL_UNSIGNED_BYTE, gl->font_tex_empty_buf);
@ -168,16 +170,37 @@ static void blit_fonts(gl_t *gl, const struct font_output *head, const struct fo
int y = head->off_y - geom->y;
y = gl->font_tex_h - head->height - y - 1;
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(head->pitch));
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(head->width));
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, head->pitch);
glTexSubImage2D(GL_TEXTURE_2D,
0, x, y, head->width, head->height,
GL_LUMINANCE, GL_UNSIGNED_BYTE, head->output);
#else
if (head->width == head->pitch)
{
glTexSubImage2D(GL_TEXTURE_2D,
0, x, y, head->width, head->height,
GL_LUMINANCE, GL_UNSIGNED_BYTE, head->output);
}
else // Slower path
{
const uint8_t *src = head->output;
for (int i = 0; i < head->height; src += head->pitch, y++)
{
glTexSubImage2D(GL_TEXTURE_2D,
0, x, y, head->width, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE, src);
}
}
#endif
head = head->next;
}
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
}
static void calculate_font_coords(gl_t *gl,

@ -49,8 +49,6 @@ void gfx_ctx_destroy(void);
void gfx_ctx_get_video_size(unsigned *width, unsigned *height);
void gfx_ctx_update_window_title(bool reset);
bool gfx_ctx_key_pressed(int key);
void gfx_ctx_check_window(bool *quit,
bool *resize, unsigned *width, unsigned *height, unsigned frame_count);

110
gfx/gl.c

@ -44,23 +44,6 @@
#include "shader_glsl.h"
#endif
// Platform specific workarounds/hacks.
#if defined(__CELLOS_LV2__) || defined(HAVE_OPENGLES)
#define NO_GL_READ_VIEWPORT
#endif
#if defined(HAVE_OPENGL_MODERN) || defined(HAVE_OPENGLES2)
#define NO_GL_FF_VERTEX
#endif
#if defined(HAVE_OPENGL_MODERN) || defined(HAVE_OPENGLES2) || defined(HAVE_PSGL)
#define NO_GL_FF_MATRIX
#endif
#if defined(ANDROID) // TODO: Figure out exactly what.
#define NO_GL_CLAMP_TO_BORDER
#endif
// Used for the last pass when rendering to the back buffer.
const GLfloat vertexes_flipped[] = {
0, 1,
@ -127,6 +110,13 @@ static bool load_fbo_proc(void)
return pglGenFramebuffers && pglBindFramebuffer && pglFramebufferTexture2D &&
pglCheckFramebufferStatus && pglDeleteFramebuffers;
}
#elif defined(HAVE_OPENGLES2)
#define pglGenFramebuffers glGenFramebuffers
#define pglBindFramebuffer glBindFramebuffer
#define pglFramebufferTexture2D glFramebufferTexture2D
#define pglCheckFramebufferStatus glCheckFramebufferStatus
#define pglDeleteFramebuffers glDeleteFramebuffers
static bool load_fbo_proc(void) { return true; }
#elif defined(HAVE_OPENGLES)
#define pglGenFramebuffers glGenFramebuffersOES
#define pglBindFramebuffer glBindFramebufferOES
@ -136,7 +126,6 @@ static bool load_fbo_proc(void)
#define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
#define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
#define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
#define glOrtho glOrthof
static bool load_fbo_proc(void) { return true; }
#else
#define pglGenFramebuffers glGenFramebuffers
@ -830,9 +819,6 @@ static void gl_update_input_size(gl_t *gl, unsigned width, unsigned height, unsi
#else
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * gl->base_size));
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, gl->tex_w, gl->tex_h, gl->texture_type,
gl->texture_fmt, gl->empty_buf);
@ -949,6 +935,40 @@ static inline void gl_copy_frame(gl_t *gl, const void *frame, unsigned width, un
{
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * gl->base_size));
#ifdef HAVE_OPENGLES2 // Have to perform pixel format conversions as well. (ARGB1555 => RGBA5551), (ARGB8888 => RGBA8888) :(
if (gl->base_size == 4) // ARGB8888 => RGBA8888
{
const uint32_t *src = (const uint32_t*)frame;
uint32_t *dst = (uint32_t*)gl->conv_buffer;
unsigned pitch_width = pitch >> 2;
// GL_RGBA + GL_UNSIGNED_BYTE apparently means in byte order, so go with little endian for now (ABGR).
for (unsigned h = 0; h < height; h++, dst += width, src += pitch_width)
{
for (unsigned w = 0; w < width; w++)
{
uint32_t col = src[w];
dst[w] = ((col << 16) & 0x00ff0000) | ((col >> 16) & 0x000000ff) | (col & 0xff00ff00);
}
}
}
else // ARGB1555 => RGBA1555
{
// Go 32-bit at once.
unsigned half_width = width >> 1;
const uint32_t *src = (const uint32_t*)frame;
uint32_t *dst = (uint32_t*)gl->conv_buffer;
unsigned pitch_width = pitch >> 2;
for (unsigned h = 0; h < height; h++, dst += half_width, src += pitch_width)
for (unsigned w = 0; w < half_width; w++)
dst[w] = (src[w] << 1) & 0xfffefffe;
}
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, width, height, gl->texture_type,
gl->texture_fmt, gl->conv_buffer);
#else
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size);
glTexSubImage2D(GL_TEXTURE_2D,
@ -974,6 +994,7 @@ static inline void gl_copy_frame(gl_t *gl, const void *frame, unsigned width, un
}
}
#endif
#endif
}
static void gl_init_textures(gl_t *gl)
@ -988,10 +1009,6 @@ static void gl_init_textures(gl_t *gl)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->tex_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->tex_filter);
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D,
0, RARCH_GL_INTERNAL_FORMAT, gl->tex_w, gl->tex_h, 0, gl->texture_type,
gl->texture_fmt, gl->empty_buf ? gl->empty_buf : NULL);
@ -1152,8 +1169,8 @@ static void gl_free(void *data)
gfx_ctx_destroy();
if (gl->empty_buf)
free(gl->empty_buf);
free(gl->empty_buf);
free(gl->conv_buffer);
free(gl);
}
@ -1176,18 +1193,16 @@ static bool resolve_extensions(gl_t *gl)
#endif
#ifdef NO_GL_CLAMP_TO_BORDER
// Doesn't support GL_CLAMP_TO_BORDER. NOTE: This will be a serious problem for some shaders.
//
// NOTE2: We still need to query if GL_CLAMP_TO_BORDER is supported even if compiling with
// OpenGL ES 1 because none of these defines are in any system headers except for what every
// Android GPU supports (which doesn't include GL_CLAMP_TO_BORDER) - move the underlying value
// for GL_CLAMP_TO_BORDER to some variable that we'll use here and query at gl_init if
// GL_CLAMP_TO_BORDER is available
// NOTE: This will be a serious problem for some shaders.
gl->border_type = GL_CLAMP_TO_EDGE;
#else
gl->border_type = GL_CLAMP_TO_BORDER;
#endif
const char *ext = (const char*)glGetString(GL_EXTENSIONS);
if (ext)
RARCH_LOG("[GL] Supported extensions: %s\n", ext);
#if defined(HAVE_PBO)
RARCH_LOG("[GL]: Using PBOs.\n");
if (!gl_query_extension("GL_ARB_pixel_buffer_object"))
@ -1197,10 +1212,6 @@ static bool resolve_extensions(gl_t *gl)
}
#endif
#ifndef GL_UNPACK_ROW_LENGTH
RARCH_WARN("[GL]: GL_UNPACK_ROW_LENGTH is not defined. Texture uploads will possibly be slower than optimal.\n");
#endif
return true;
}
@ -1289,7 +1300,7 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
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.
@ -1308,7 +1319,10 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
gl->texture_fmt = video->rgb32 ? RARCH_GL_FORMAT32 : RARCH_GL_FORMAT16;
gl->base_size = video->rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
#ifndef HAVE_OPENGLES
glEnable(GL_TEXTURE_2D);
#endif
glDisable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glClearColor(0, 0, 0, 1);
@ -1337,6 +1351,17 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
// 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);
#ifdef HAVE_OPENGLES2
gl->conv_buffer = calloc(gl->tex_w * gl->tex_h, gl->base_size);
if (!gl->conv_buffer)
{
gfx_ctx_destroy();
free(gl);
return NULL;
}
#endif
gl_init_textures(gl);
for (unsigned i = 0; i < TEXTURES; i++)
@ -1347,18 +1372,17 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
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].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].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;
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();

@ -176,6 +176,7 @@ typedef struct gl
GLuint tex_filter;
void *empty_buf;
void *conv_buffer;
unsigned frame_count;
@ -245,8 +246,8 @@ extern PFNGLACTIVETEXTUREPROC pglActiveTexture;
#elif defined(HAVE_OPENGLES)
#define RARCH_GL_INTERNAL_FORMAT GL_RGBA
#define RARCH_GL_TEXTURE_TYPE GL_RGBA
#define RARCH_GL_FORMAT32 GL_UNSIGNED_INT
#define RARCH_GL_FORMAT16 GL_UNSIGNED_SHORT
#define RARCH_GL_FORMAT32 GL_UNSIGNED_BYTE
#define RARCH_GL_FORMAT16 GL_UNSIGNED_SHORT_5_5_5_1
#else
#define RARCH_GL_INTERNAL_FORMAT GL_RGBA
#define RARCH_GL_TEXTURE_TYPE GL_BGRA
@ -254,6 +255,27 @@ extern PFNGLACTIVETEXTUREPROC pglActiveTexture;
#define RARCH_GL_FORMAT16 GL_UNSIGNED_SHORT_1_5_5_5_REV
#endif
// Platform specific workarounds/hacks.
#if defined(__CELLOS_LV2__) || defined(HAVE_OPENGLES)
#define NO_GL_READ_VIEWPORT
#endif
#if defined(HAVE_OPENGL_MODERN) || defined(HAVE_OPENGLES2)
#define NO_GL_FF_VERTEX
#endif
#if defined(HAVE_OPENGL_MODERN) || defined(HAVE_OPENGLES2) || defined(HAVE_PSGL)
#define NO_GL_FF_MATRIX
#endif
#if defined(HAVE_OPENGLES2) // TODO: Figure out exactly what.
#define NO_GL_CLAMP_TO_BORDER
#endif
#if defined(HAVE_OPENGLES2) // It's an extension. Don't bother checking for it atm.
#undef GL_UNPACK_ROW_LENGTH
#endif
void gl_shader_use(unsigned index);
void gl_set_projection(gl_t *gl, struct gl_ortho *ortho, bool allow_rotate);
void gl_set_viewport(gl_t *gl, unsigned width, unsigned height, bool force_full, bool allow_rotate);

@ -292,7 +292,8 @@ static void *sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu
#ifdef HAVE_X11
RARCH_LOG("Suspending screensaver (X11).\n");
SDL_SysWMinfo wm_info;
if (gfx_ctx_get_wm_info(&wm_info))
SDL_VERSION(&wm_info.version);
if (SDL_GetWMInfo(&wm_info) == 1)
gfx_suspend_screensaver(wm_info.info.x11.window);
else
RARCH_ERR("Failed to suspend screensaver.\n");

@ -60,6 +60,33 @@
#include "gl_common.h"
#include "image.h"
#if defined(HAVE_OPENGLES2) || defined(HAVE_OPENGL_MODERN)
#define pglCreateProgram glCreateProgram
#define pglUseProgram glUseProgram
#define pglCreateShader glCreateShader
#define pglDeleteShader glDeleteShader
#define pglShaderSource glShaderSource
#define pglCompileShader glCompileShader
#define pglAttachShader glAttachShader
#define pglDetachShader glDetachShader
#define pglLinkProgram glLinkProgram
#define pglGetUniformLocation glGetUniformLocation
#define pglUniform1i glUniform1i
#define pglUniform1f glUniform1f
#define pglUniform2fv glUniform2fv
#define pglUniform4fv glUniform4fv
#define pglUniformMatrix4fv glUniformMatrix4fv
#define pglGetShaderiv glGetShaderiv
#define pglGetShaderInfoLog glGetShaderInfoLog
#define pglGetProgramiv glGetProgramiv
#define pglGetProgramInfoLog glGetProgramInfoLog
#define pglDeleteProgram glDeleteProgram
#define pglGetAttachedShaders glGetAttachedShaders
#define pglGetAttribLocation glGetAttribLocation
#define pglEnableVertexAttribArray glEnableVertexAttribArray
#define pglDisableVertexAttribArray glDisableVertexAttribArray
#define pglVertexAttribPointer glVertexAttribPointer
#else
static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL;
static PFNGLUSEPROGRAMPROC pglUseProgram = NULL;
static PFNGLCREATESHADERPROC pglCreateShader = NULL;
@ -85,6 +112,13 @@ static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation = NULL;
static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray = NULL;
static PFNGLDISABLEVERTEXATTRIBARRAYPROC pglDisableVertexAttribArray = NULL;
static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL;
#endif
#ifdef HAVE_OPENGLES2
#define BORDER_FUNC GL_CLAMP_TO_EDGE
#else
#define BORDER_FUNC GL_CLAMP_TO_BORDER
#endif
#define MAX_PROGRAMS 16
#define MAX_TEXTURES 8
@ -390,15 +424,17 @@ static bool get_texture_image(const char *shader_path, xmlNodePtr ptr)
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1);
glBindTexture(GL_TEXTURE_2D, gl_teximage[gl_teximage_cnt]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, BORDER_FUNC);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, BORDER_FUNC);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D,
0, GL_RGBA, img.width, img.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, img.pixels);
0, RARCH_GL_INTERNAL_FORMAT,
img.width, img.height, 0, RARCH_GL_TEXTURE_TYPE, GL_UNSIGNED_INT, img.pixels);
pglActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
@ -893,17 +929,14 @@ static void gl_glsl_reset_attrib(void)
// Platforms with broken get_proc_address.
// Assume functions are available without proc_address.
#ifdef __PSL1GHT__
#define LOAD_GL_SYM(SYM) pgl##SYM = gl##SYM;
#else
#define LOAD_GL_SYM(SYM) if (!pgl##SYM) { \
gfx_ctx_proc_t sym = gfx_ctx_get_proc_address("gl" #SYM); \
memcpy(&(pgl##SYM), &sym, sizeof(sym)); \
}
#endif
bool gl_glsl_init(const char *path)
{
#if !defined(HAVE_OPENGLES2) && !defined(HAVE_OPENGL_MODERN)
// Load shader functions.
LOAD_GL_SYM(CreateProgram);
LOAD_GL_SYM(UseProgram);
@ -946,6 +979,7 @@ bool gl_glsl_init(const char *path)
RARCH_ERR("GLSL shaders aren't supported by your OpenGL driver.\n");
return false;
}
#endif
#ifdef HAVE_XML
struct shader_program progs[MAX_PROGRAMS];

@ -182,7 +182,15 @@ static void *sdl_input_init(void)
static bool sdl_key_pressed(int key)
{
return key < RETROK_LAST && gfx_ctx_key_pressed(keysym_lut[key]);
if (key >= RETROK_LAST)
return false;
int num_keys;
Uint8 *keymap = SDL_GetKeyState(&num_keys);
if (key >= num_keys)
return false;
return keymap[key];
}
#ifndef HAVE_DINPUT

@ -145,6 +145,6 @@ check_pkgconf PYTHON python3
add_define_make OS "$OS"
# Creates config.mk and config.h.
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE LIBPNG DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO PBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 SINC FIXED_POINT BSV_MOVIE RPI"
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL GLES DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE LIBPNG DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO PBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 SINC FIXED_POINT BSV_MOVIE RPI"
create_config_make config.mk $VARS
create_config_header config.h $VARS

@ -6,6 +6,7 @@ HAVE_DYLIB=auto # Enable dynamic loading support
HAVE_NETPLAY=auto # Enable netplay support
HAVE_CONFIGFILE=yes # Disable support for config file
HAVE_OPENGL=yes # Disable OpenGL support
HAVE_GLES=no # Use X/EGL instead of desktop GL (experimental)
HAVE_CG=auto # Enable Cg shader support
HAVE_XML=auto # Enable bSNES-style XML shader support
HAVE_FBO=auto # Enable render-to-texture (FBO) support