Rework overlay driver interface.

Takes multiple images, each with individual positions, textures, etc.
This commit is contained in:
Themaister 2013-10-15 16:06:59 +02:00
parent 3c3e90b0df
commit 76c92bb0b4
5 changed files with 135 additions and 74 deletions

View File

@ -332,14 +332,21 @@ typedef struct input_driver
struct rarch_viewport; struct rarch_viewport;
#ifdef HAVE_OVERLAY #ifdef HAVE_OVERLAY
struct video_overlay_image
{
const uint32_t *image;
unsigned width;
unsigned height;
};
typedef struct video_overlay_interface typedef struct video_overlay_interface
{ {
void (*enable)(void *data, bool state); void (*enable)(void *data, bool state);
bool (*load)(void *data, const uint32_t *image, unsigned width, unsigned height); bool (*load)(void *data, const struct video_overlay_image *images, unsigned num_images);
void (*tex_geom)(void *data, float x, float y, float w, float h); void (*tex_geom)(void *data, unsigned image, float x, float y, float w, float h);
void (*vertex_geom)(void *data, float x, float y, float w, float h); void (*vertex_geom)(void *data, unsigned image, float x, float y, float w, float h);
void (*full_screen)(void *data, bool enable); void (*full_screen)(void *data, bool enable);
void (*set_alpha)(void *data, float mod); void (*set_alpha)(void *data, unsigned image, float mod);
} video_overlay_interface_t; } video_overlay_interface_t;
#endif #endif

115
gfx/gl.c
View File

@ -120,8 +120,10 @@ static inline bool gl_query_extension(gl_t *gl, const char *ext)
#ifdef HAVE_OVERLAY #ifdef HAVE_OVERLAY
static void gl_render_overlay(void *data); static void gl_render_overlay(void *data);
static void gl_overlay_vertex_geom(void *data, static void gl_overlay_vertex_geom(void *data,
unsigned image,
float x, float y, float w, float h); float x, float y, float w, float h);
static void gl_overlay_tex_geom(void *data, static void gl_overlay_tex_geom(void *data,
unsigned image,
float x, float y, float w, float h); float x, float y, float w, float h);
#endif #endif
@ -1547,6 +1549,19 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
return true; return true;
} }
#ifdef HAVE_OVERLAY
static void gl_free_overlay(gl_t *gl)
{
for (unsigned i = 0; i < gl->overlays; i++)
if (gl->overlay[i].tex)
glDeleteTextures(1, &gl->overlay[i].tex);
free(gl->overlay);
gl->overlay = NULL;
gl->overlays = 0;
}
#endif
static void gl_free(void *data) static void gl_free(void *data)
{ {
#ifdef RARCH_CONSOLE #ifdef RARCH_CONSOLE
@ -1584,8 +1599,7 @@ static void gl_free(void *data)
#endif #endif
#ifdef HAVE_OVERLAY #ifdef HAVE_OVERLAY
if (gl->tex_overlay) gl_free_overlay(gl);
glDeleteTextures(1, &gl->tex_overlay);
#endif #endif
#if defined(HAVE_PSGL) #if defined(HAVE_PSGL)
@ -2404,58 +2418,73 @@ static void gl_restart(void)
#endif #endif
#ifdef HAVE_OVERLAY #ifdef HAVE_OVERLAY
static bool gl_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height) static void gl_free_overlay(gl_t *gl);
static bool gl_overlay_load(void *data, const struct video_overlay_image *images, unsigned num_images)
{ {
gl_t *gl = (gl_t*)data; gl_t *gl = (gl_t*)data;
if (!gl->tex_overlay) gl_free_overlay(gl);
glGenTextures(1, &gl->tex_overlay); gl->overlay = (struct gl_overlay_data*)calloc(num_images, sizeof(*gl->overlay));
if (!gl->overlay)
return false;
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay); gl->overlays = num_images;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); for (unsigned i = 0; i < num_images; i++)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); struct gl_overlay_data *data = &gl->overlay[i];
glGenTextures(1, &data->tex);
glBindTexture(GL_TEXTURE_2D, data->tex);
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);
#ifndef HAVE_PSGL #ifndef HAVE_PSGL
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t))); glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(images[i].width * sizeof(uint32_t)));
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32, glTexImage2D(GL_TEXTURE_2D, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32,
width, height, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32, images[i].width, images[i].height, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32,
RARCH_GL_FORMAT32, image); RARCH_GL_FORMAT32, images[i].image);
gl_overlay_tex_geom(gl, 0, 0, 1, 1); // Default. Stretch to whole screen. gl_overlay_tex_geom(gl, i, 0, 0, 1, 1); // Default. Stretch to whole screen.
gl_overlay_vertex_geom(gl, 0, 0, 1, 1); gl_overlay_vertex_geom(gl, i, 0, 0, 1, 1);
gl->overlay[i].alpha_mod = 1.0f;
}
return true; return true;
} }
static void gl_overlay_tex_geom(void *data, static void gl_overlay_tex_geom(void *data,
unsigned image,
GLfloat x, GLfloat y, GLfloat x, GLfloat y,
GLfloat w, GLfloat h) GLfloat w, GLfloat h)
{ {
gl_t *gl = (gl_t*)data; gl_t *gl = (gl_t*)data;
struct gl_overlay_data *o = &gl->overlay[image];
gl->overlay_tex_coord[0] = x; gl->overlay_tex_coord[1] = y; o->tex_coord[0] = x; o->tex_coord[1] = y;
gl->overlay_tex_coord[2] = x + w; gl->overlay_tex_coord[3] = y; o->tex_coord[2] = x + w; o->tex_coord[3] = y;
gl->overlay_tex_coord[4] = x; gl->overlay_tex_coord[5] = y + h; o->tex_coord[4] = x; o->tex_coord[5] = y + h;
gl->overlay_tex_coord[6] = x + w; gl->overlay_tex_coord[7] = y + h; o->tex_coord[6] = x + w; o->tex_coord[7] = y + h;
} }
static void gl_overlay_vertex_geom(void *data, static void gl_overlay_vertex_geom(void *data,
unsigned image,
float x, float y, float x, float y,
float w, float h) float w, float h)
{ {
gl_t *gl = (gl_t*)data; gl_t *gl = (gl_t*)data;
struct gl_overlay_data *o = &gl->overlay[image];
// Flipped, so we preserve top-down semantics. // Flipped, so we preserve top-down semantics.
y = 1.0f - y; y = 1.0f - y;
h = -h; h = -h;
gl->overlay_vertex_coord[0] = x; gl->overlay_vertex_coord[1] = y; o->vertex_coord[0] = x; o->vertex_coord[1] = y;
gl->overlay_vertex_coord[2] = x + w; gl->overlay_vertex_coord[3] = y; o->vertex_coord[2] = x + w; o->vertex_coord[3] = y;
gl->overlay_vertex_coord[4] = x; gl->overlay_vertex_coord[5] = y + h; o->vertex_coord[4] = x; o->vertex_coord[5] = y + h;
gl->overlay_vertex_coord[6] = x + w; gl->overlay_vertex_coord[7] = y + h; o->vertex_coord[6] = x + w; o->vertex_coord[7] = y + h;
} }
static void gl_overlay_enable(void *data, bool state) static void gl_overlay_enable(void *data, bool state)
@ -2472,49 +2501,49 @@ static void gl_overlay_full_screen(void *data, bool enable)
gl->overlay_full_screen = enable; gl->overlay_full_screen = enable;
} }
static void gl_overlay_set_alpha(void *data, float mod) static void gl_overlay_set_alpha(void *data, unsigned image, float mod)
{ {
gl_t *gl = (gl_t*)data; gl_t *gl = (gl_t*)data;
gl->overlay_alpha_mod = mod; gl->overlay[image].alpha_mod = mod;
} }
static void gl_render_overlay(void *data) static void gl_render_overlay(void *data)
{ {
gl_t *gl = (gl_t*)data; gl_t *gl = (gl_t*)data;
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay); GLfloat white_color_mod[16] = {
1.0f, 1.0f, 1.0f, 1.0f,
const GLfloat white_color_mod[16] = { 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
}; };
if (gl->shader) if (gl->shader)
gl->shader->use(GL_SHADER_STOCK_BLEND); gl->shader->use(GL_SHADER_STOCK_BLEND);
glEnable(GL_BLEND); glEnable(GL_BLEND);
gl->coords.vertex = gl->overlay_vertex_coord;
gl->coords.tex_coord = gl->overlay_tex_coord;
gl->coords.color = white_color_mod;
gl_shader_set_coords(gl, &gl->coords, &gl->mvp_no_rot);
if (gl->overlay_full_screen) if (gl->overlay_full_screen)
{
glViewport(0, 0, gl->win_width, gl->win_height); glViewport(0, 0, gl->win_width, gl->win_height);
for (unsigned i = 0; i < gl->overlays; i++)
{
glBindTexture(GL_TEXTURE_2D, gl->overlay[i].tex);
for (unsigned j = 0; j < 4; j++)
white_color_mod[3 + j * 4] = gl->overlay[i].alpha_mod;
gl->coords.vertex = gl->overlay[i].vertex_coord;
gl->coords.tex_coord = gl->overlay[i].tex_coord;
gl->coords.color = white_color_mod;
gl_shader_set_coords(gl, &gl->coords, &gl->mvp_no_rot);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
} }
else
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_BLEND); glDisable(GL_BLEND);
gl->coords.vertex = gl->vertex_ptr; gl->coords.vertex = gl->vertex_ptr;
gl->coords.tex_coord = gl->tex_coords; gl->coords.tex_coord = gl->tex_coords;
gl->coords.color = gl->white_color_ptr; gl->coords.color = gl->white_color_ptr;
if (gl->overlay_full_screen)
glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
} }
static const video_overlay_interface_t gl_overlay_interface = { static const video_overlay_interface_t gl_overlay_interface = {

View File

@ -136,6 +136,14 @@ typedef struct gl_shader_backend gl_shader_backend_t;
#define MAX_SHADERS 16 #define MAX_SHADERS 16
#define MAX_TEXTURES 8 #define MAX_TEXTURES 8
struct gl_overlay_data
{
GLuint tex;
GLfloat tex_coord[8];
GLfloat vertex_coord[8];
GLfloat alpha_mod;
};
typedef struct gl typedef struct gl
{ {
const gfx_ctx_driver_t *ctx_driver; const gfx_ctx_driver_t *ctx_driver;
@ -219,13 +227,10 @@ typedef struct gl
video_info_t video_info; video_info_t video_info;
#ifdef HAVE_OVERLAY #ifdef HAVE_OVERLAY
// Overlay rendering struct gl_overlay_data *overlay;
unsigned overlays;
bool overlay_enable; bool overlay_enable;
bool overlay_full_screen; bool overlay_full_screen;
GLuint tex_overlay;
GLfloat overlay_tex_coord[8];
GLfloat overlay_vertex_coord[8];
GLfloat overlay_alpha_mod;
#endif #endif
#if !defined(HAVE_OPENGLES) && defined(HAVE_FFMPEG) #if !defined(HAVE_OPENGLES) && defined(HAVE_FFMPEG)

View File

@ -112,14 +112,20 @@ typedef struct thread_video
struct struct
{ {
unsigned index;
float x, y, w, h; float x, y, w, h;
} rect; } rect;
struct struct
{ {
const uint32_t *data; unsigned index;
unsigned width; float mod;
unsigned height; } alpha;
struct
{
const struct video_overlay_image *data;
unsigned num;
} image; } image;
struct struct
@ -242,13 +248,13 @@ static void thread_loop(void *data)
case CMD_OVERLAY_LOAD: case CMD_OVERLAY_LOAD:
thr->cmd_data.b = thr->overlay->load(thr->driver_data, thr->cmd_data.b = thr->overlay->load(thr->driver_data,
thr->cmd_data.image.data, thr->cmd_data.image.data,
thr->cmd_data.image.width, thr->cmd_data.image.num);
thr->cmd_data.image.height);
thread_reply(thr, CMD_OVERLAY_LOAD); thread_reply(thr, CMD_OVERLAY_LOAD);
break; break;
case CMD_OVERLAY_TEX_GEOM: case CMD_OVERLAY_TEX_GEOM:
thr->overlay->tex_geom(thr->driver_data, thr->overlay->tex_geom(thr->driver_data,
thr->cmd_data.rect.index,
thr->cmd_data.rect.x, thr->cmd_data.rect.x,
thr->cmd_data.rect.y, thr->cmd_data.rect.y,
thr->cmd_data.rect.w, thr->cmd_data.rect.w,
@ -258,6 +264,7 @@ static void thread_loop(void *data)
case CMD_OVERLAY_VERTEX_GEOM: case CMD_OVERLAY_VERTEX_GEOM:
thr->overlay->vertex_geom(thr->driver_data, thr->overlay->vertex_geom(thr->driver_data,
thr->cmd_data.rect.index,
thr->cmd_data.rect.x, thr->cmd_data.rect.x,
thr->cmd_data.rect.y, thr->cmd_data.rect.y,
thr->cmd_data.rect.w, thr->cmd_data.rect.w,
@ -271,7 +278,7 @@ static void thread_loop(void *data)
break; break;
case CMD_OVERLAY_SET_ALPHA: case CMD_OVERLAY_SET_ALPHA:
thr->overlay->set_alpha(thr->driver_data, thr->cmd_data.f); thr->overlay->set_alpha(thr->driver_data, thr->cmd_data.alpha.index, thr->cmd_data.alpha.mod);
thread_reply(thr, CMD_OVERLAY_SET_ALPHA); thread_reply(thr, CMD_OVERLAY_SET_ALPHA);
break; break;
#endif #endif
@ -573,20 +580,20 @@ static void thread_overlay_enable(void *data, bool state)
thread_wait_reply(thr, CMD_OVERLAY_ENABLE); thread_wait_reply(thr, CMD_OVERLAY_ENABLE);
} }
static bool thread_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height) static bool thread_overlay_load(void *data, const struct video_overlay_image *images, unsigned num_images)
{ {
thread_video_t *thr = (thread_video_t*)data; thread_video_t *thr = (thread_video_t*)data;
thr->cmd_data.image.data = image; thr->cmd_data.image.data = images;
thr->cmd_data.image.width = width; thr->cmd_data.image.num = num_images;
thr->cmd_data.image.height = height;
thread_send_cmd(thr, CMD_OVERLAY_LOAD); thread_send_cmd(thr, CMD_OVERLAY_LOAD);
thread_wait_reply(thr, CMD_OVERLAY_LOAD); thread_wait_reply(thr, CMD_OVERLAY_LOAD);
return thr->cmd_data.b; return thr->cmd_data.b;
} }
static void thread_overlay_tex_geom(void *data, float x, float y, float w, float h) static void thread_overlay_tex_geom(void *data, unsigned index, float x, float y, float w, float h)
{ {
thread_video_t *thr = (thread_video_t*)data; thread_video_t *thr = (thread_video_t*)data;
thr->cmd_data.rect.index = index;
thr->cmd_data.rect.x = x; thr->cmd_data.rect.x = x;
thr->cmd_data.rect.y = y; thr->cmd_data.rect.y = y;
thr->cmd_data.rect.w = w; thr->cmd_data.rect.w = w;
@ -595,9 +602,10 @@ static void thread_overlay_tex_geom(void *data, float x, float y, float w, float
thread_wait_reply(thr, CMD_OVERLAY_TEX_GEOM); thread_wait_reply(thr, CMD_OVERLAY_TEX_GEOM);
} }
static void thread_overlay_vertex_geom(void *data, float x, float y, float w, float h) static void thread_overlay_vertex_geom(void *data, unsigned index, float x, float y, float w, float h)
{ {
thread_video_t *thr = (thread_video_t*)data; thread_video_t *thr = (thread_video_t*)data;
thr->cmd_data.rect.index = index;
thr->cmd_data.rect.x = x; thr->cmd_data.rect.x = x;
thr->cmd_data.rect.y = y; thr->cmd_data.rect.y = y;
thr->cmd_data.rect.w = w; thr->cmd_data.rect.w = w;
@ -614,10 +622,11 @@ static void thread_overlay_full_screen(void *data, bool enable)
thread_wait_reply(thr, CMD_OVERLAY_FULL_SCREEN); thread_wait_reply(thr, CMD_OVERLAY_FULL_SCREEN);
} }
static void thread_overlay_set_alpha(void *data, float mod) static void thread_overlay_set_alpha(void *data, unsigned index, float mod)
{ {
thread_video_t *thr = (thread_video_t*)data; thread_video_t *thr = (thread_video_t*)data;
thr->cmd_data.f = mod; thr->cmd_data.alpha.index = index;
thr->cmd_data.alpha.mod = mod;
thread_send_cmd(thr, CMD_OVERLAY_SET_ALPHA); thread_send_cmd(thr, CMD_OVERLAY_SET_ALPHA);
thread_wait_reply(thr, CMD_OVERLAY_SET_ALPHA); thread_wait_reply(thr, CMD_OVERLAY_SET_ALPHA);
} }

View File

@ -190,7 +190,7 @@ void input_overlay_set_scale_factor(input_overlay_t *ol, float scale)
for (size_t i = 0; i < ol->size; i++) for (size_t i = 0; i < ol->size; i++)
input_overlay_scale(&ol->overlays[i], scale); input_overlay_scale(&ol->overlays[i], scale);
ol->iface->vertex_geom(ol->iface_data, ol->iface->vertex_geom(ol->iface_data, 0,
ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h); ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
} }
@ -262,8 +262,8 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de
} }
} }
desc->x = strtod(x, NULL) / width; desc->x = strtod(x, NULL) / width;
desc->y = strtod(y, NULL) / height; desc->y = strtod(y, NULL) / height;
if (!strcmp(box, "radial")) if (!strcmp(box, "radial"))
desc->hitbox = OVERLAY_HITBOX_RADIAL; desc->hitbox = OVERLAY_HITBOX_RADIAL;
@ -516,8 +516,13 @@ input_overlay_t *input_overlay_new(const char *overlay)
goto error; goto error;
ol->active = &ol->overlays[0]; ol->active = &ol->overlays[0];
ol->iface->load(ol->iface_data, ol->active->image, ol->active->width, ol->active->height); struct video_overlay_image image = {
ol->iface->vertex_geom(ol->iface_data, ol->active->image,
ol->active->width,
ol->active->height,
};
ol->iface->load(ol->iface_data, &image, 1);
ol->iface->vertex_geom(ol->iface_data, 0,
ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h); ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
ol->iface->full_screen(ol->iface_data, ol->active->full_screen); ol->iface->full_screen(ol->iface_data, ol->active->full_screen);
@ -628,10 +633,16 @@ void input_overlay_next(input_overlay_t *ol)
ol->index = ol->next_index; ol->index = ol->next_index;
ol->active = &ol->overlays[ol->index]; ol->active = &ol->overlays[ol->index];
ol->iface->load(ol->iface_data, ol->active->image, ol->active->width, ol->active->height); struct video_overlay_image image = {
ol->iface->vertex_geom(ol->iface_data, ol->active->image,
ol->active->width,
ol->active->height,
};
ol->iface->load(ol->iface_data, &image, 1);
ol->iface->vertex_geom(ol->iface_data, 0,
ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h); ol->active->mod_x, ol->active->mod_y, ol->active->mod_w, ol->active->mod_h);
ol->iface->full_screen(ol->iface_data, ol->active->full_screen); ol->iface->full_screen(ol->iface_data, ol->active->full_screen);
ol->iface->set_alpha(ol->iface_data, 0, g_settings.input.overlay_opacity);
ol->blocked = true; ol->blocked = true;
ol->next_index = (ol->index + 1) % ol->size; ol->next_index = (ol->index + 1) % ol->size;
} }
@ -656,7 +667,7 @@ void input_overlay_free(input_overlay_t *ol)
void input_overlay_set_alpha_mod(input_overlay_t *ol, float mod) void input_overlay_set_alpha_mod(input_overlay_t *ol, float mod)
{ {
ol->iface->set_alpha(ol->iface_data, mod); ol->iface->set_alpha(ol->iface_data, 0, mod);
} }