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;
#ifdef HAVE_OVERLAY
struct video_overlay_image
{
const uint32_t *image;
unsigned width;
unsigned height;
};
typedef struct video_overlay_interface
{
void (*enable)(void *data, bool state);
bool (*load)(void *data, const uint32_t *image, unsigned width, unsigned height);
void (*tex_geom)(void *data, float x, float y, float w, float h);
void (*vertex_geom)(void *data, float x, float y, float w, float h);
bool (*load)(void *data, const struct video_overlay_image *images, unsigned num_images);
void (*tex_geom)(void *data, unsigned image, 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 (*set_alpha)(void *data, float mod);
void (*set_alpha)(void *data, unsigned image, float mod);
} video_overlay_interface_t;
#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
static void gl_render_overlay(void *data);
static void gl_overlay_vertex_geom(void *data,
unsigned image,
float x, float y, float w, float h);
static void gl_overlay_tex_geom(void *data,
unsigned image,
float x, float y, float w, float h);
#endif
@ -1547,6 +1549,19 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
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)
{
#ifdef RARCH_CONSOLE
@ -1584,8 +1599,7 @@ static void gl_free(void *data)
#endif
#ifdef HAVE_OVERLAY
if (gl->tex_overlay)
glDeleteTextures(1, &gl->tex_overlay);
gl_free_overlay(gl);
#endif
#if defined(HAVE_PSGL)
@ -2404,58 +2418,73 @@ static void gl_restart(void)
#endif
#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;
if (!gl->tex_overlay)
glGenTextures(1, &gl->tex_overlay);
gl_free_overlay(gl);
gl->overlay = (struct gl_overlay_data*)calloc(num_images, sizeof(*gl->overlay));
if (!gl->overlay)
return false;
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay);
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);
gl->overlays = num_images;
for (unsigned i = 0; i < num_images; i++)
{
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
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t)));
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(images[i].width * sizeof(uint32_t)));
#endif
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,
RARCH_GL_FORMAT32, image);
glTexImage2D(GL_TEXTURE_2D, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32,
images[i].width, images[i].height, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32,
RARCH_GL_FORMAT32, images[i].image);
gl_overlay_tex_geom(gl, 0, 0, 1, 1); // Default. Stretch to whole screen.
gl_overlay_vertex_geom(gl, 0, 0, 1, 1);
gl_overlay_tex_geom(gl, i, 0, 0, 1, 1); // Default. Stretch to whole screen.
gl_overlay_vertex_geom(gl, i, 0, 0, 1, 1);
gl->overlay[i].alpha_mod = 1.0f;
}
return true;
}
static void gl_overlay_tex_geom(void *data,
unsigned image,
GLfloat x, GLfloat y,
GLfloat w, GLfloat h)
{
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;
gl->overlay_tex_coord[2] = x + w; gl->overlay_tex_coord[3] = y;
gl->overlay_tex_coord[4] = x; gl->overlay_tex_coord[5] = y + h;
gl->overlay_tex_coord[6] = x + w; gl->overlay_tex_coord[7] = y + h;
o->tex_coord[0] = x; o->tex_coord[1] = y;
o->tex_coord[2] = x + w; o->tex_coord[3] = y;
o->tex_coord[4] = x; o->tex_coord[5] = y + h;
o->tex_coord[6] = x + w; o->tex_coord[7] = y + h;
}
static void gl_overlay_vertex_geom(void *data,
unsigned image,
float x, float y,
float w, float h)
{
gl_t *gl = (gl_t*)data;
struct gl_overlay_data *o = &gl->overlay[image];
// Flipped, so we preserve top-down semantics.
y = 1.0f - y;
h = -h;
gl->overlay_vertex_coord[0] = x; gl->overlay_vertex_coord[1] = y;
gl->overlay_vertex_coord[2] = x + w; gl->overlay_vertex_coord[3] = y;
gl->overlay_vertex_coord[4] = x; gl->overlay_vertex_coord[5] = y + h;
gl->overlay_vertex_coord[6] = x + w; gl->overlay_vertex_coord[7] = y + h;
o->vertex_coord[0] = x; o->vertex_coord[1] = y;
o->vertex_coord[2] = x + w; o->vertex_coord[3] = y;
o->vertex_coord[4] = x; o->vertex_coord[5] = y + h;
o->vertex_coord[6] = x + w; o->vertex_coord[7] = y + h;
}
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;
}
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->overlay_alpha_mod = mod;
gl->overlay[image].alpha_mod = mod;
}
static void gl_render_overlay(void *data)
{
gl_t *gl = (gl_t*)data;
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay);
const GLfloat white_color_mod[16] = {
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
1.0f, 1.0f, 1.0f, gl->overlay_alpha_mod,
GLfloat white_color_mod[16] = {
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
};
if (gl->shader)
gl->shader->use(GL_SHADER_STOCK_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)
{
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);
glViewport(gl->vp.x, gl->vp.y, gl->vp.width, gl->vp.height);
}
else
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_BLEND);
gl->coords.vertex = gl->vertex_ptr;
gl->coords.tex_coord = gl->tex_coords;
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 = {

View File

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

View File

@ -112,14 +112,20 @@ typedef struct thread_video
struct
{
unsigned index;
float x, y, w, h;
} rect;
struct
{
const uint32_t *data;
unsigned width;
unsigned height;
unsigned index;
float mod;
} alpha;
struct
{
const struct video_overlay_image *data;
unsigned num;
} image;
struct
@ -242,13 +248,13 @@ static void thread_loop(void *data)
case CMD_OVERLAY_LOAD:
thr->cmd_data.b = thr->overlay->load(thr->driver_data,
thr->cmd_data.image.data,
thr->cmd_data.image.width,
thr->cmd_data.image.height);
thr->cmd_data.image.num);
thread_reply(thr, CMD_OVERLAY_LOAD);
break;
case CMD_OVERLAY_TEX_GEOM:
thr->overlay->tex_geom(thr->driver_data,
thr->cmd_data.rect.index,
thr->cmd_data.rect.x,
thr->cmd_data.rect.y,
thr->cmd_data.rect.w,
@ -258,6 +264,7 @@ static void thread_loop(void *data)
case CMD_OVERLAY_VERTEX_GEOM:
thr->overlay->vertex_geom(thr->driver_data,
thr->cmd_data.rect.index,
thr->cmd_data.rect.x,
thr->cmd_data.rect.y,
thr->cmd_data.rect.w,
@ -271,7 +278,7 @@ static void thread_loop(void *data)
break;
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);
break;
#endif
@ -573,20 +580,20 @@ static void thread_overlay_enable(void *data, bool state)
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;
thr->cmd_data.image.data = image;
thr->cmd_data.image.width = width;
thr->cmd_data.image.height = height;
thr->cmd_data.image.data = images;
thr->cmd_data.image.num = num_images;
thread_send_cmd(thr, CMD_OVERLAY_LOAD);
thread_wait_reply(thr, CMD_OVERLAY_LOAD);
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;
thr->cmd_data.rect.index = index;
thr->cmd_data.rect.x = x;
thr->cmd_data.rect.y = y;
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);
}
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;
thr->cmd_data.rect.index = index;
thr->cmd_data.rect.x = x;
thr->cmd_data.rect.y = y;
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);
}
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;
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_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++)
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);
}
@ -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->y = strtod(y, NULL) / height;
desc->x = strtod(x, NULL) / width;
desc->y = strtod(y, NULL) / height;
if (!strcmp(box, "radial"))
desc->hitbox = OVERLAY_HITBOX_RADIAL;
@ -516,8 +516,13 @@ input_overlay_t *input_overlay_new(const char *overlay)
goto error;
ol->active = &ol->overlays[0];
ol->iface->load(ol->iface_data, ol->active->image, ol->active->width, ol->active->height);
ol->iface->vertex_geom(ol->iface_data,
struct video_overlay_image image = {
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->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->active = &ol->overlays[ol->index];
ol->iface->load(ol->iface_data, ol->active->image, ol->active->width, ol->active->height);
ol->iface->vertex_geom(ol->iface_data,
struct video_overlay_image image = {
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->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->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)
{
ol->iface->set_alpha(ol->iface_data, mod);
ol->iface->set_alpha(ol->iface_data, 0, mod);
}