From 5eb7432fff141e72b06ec999edec8ebbaedbe27b Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 19 Dec 2012 13:26:11 +0100 Subject: [PATCH] Add overlay rendering to GL. This allows e.g. Android to render a keypad overlay for touch. --- gfx/context/androidegl_ctx.c | 1 + gfx/context/drm_egl_ctx.c | 1 + gfx/context/glx_ctx.c | 1 + gfx/context/ps3_ctx.c | 1 + gfx/context/sdl_ctx.c | 1 + gfx/context/vc_egl_ctx.c | 1 + gfx/context/wgl_ctx.c | 1 + gfx/context/xdk_ctx.c | 1 + gfx/context/xegl_ctx.c | 1 + gfx/gfx_context.h | 4 ++ gfx/gl.c | 77 +++++++++++++++++++++++++++++++++++- gfx/gl_common.h | 17 ++++++++ 12 files changed, 106 insertions(+), 1 deletion(-) diff --git a/gfx/context/androidegl_ctx.c b/gfx/context/androidegl_ctx.c index 81d391681c..ef628b0bfa 100644 --- a/gfx/context/androidegl_ctx.c +++ b/gfx/context/androidegl_ctx.c @@ -548,6 +548,7 @@ const gfx_ctx_driver_t gfx_ctx_android = { NULL, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "android", #ifdef HAVE_RMENU gfx_ctx_set_blend, diff --git a/gfx/context/drm_egl_ctx.c b/gfx/context/drm_egl_ctx.c index 2953db6f4c..7fc9ca8f9c 100644 --- a/gfx/context/drm_egl_ctx.c +++ b/gfx/context/drm_egl_ctx.c @@ -651,6 +651,7 @@ const gfx_ctx_driver_t gfx_ctx_drm_egl = { gfx_ctx_get_proc_address, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "drm-egl", }; diff --git a/gfx/context/glx_ctx.c b/gfx/context/glx_ctx.c index a55300bcde..5899c76dc5 100644 --- a/gfx/context/glx_ctx.c +++ b/gfx/context/glx_ctx.c @@ -598,6 +598,7 @@ const gfx_ctx_driver_t gfx_ctx_glx = { gfx_ctx_get_proc_address, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "glx", }; diff --git a/gfx/context/ps3_ctx.c b/gfx/context/ps3_ctx.c index 924bb5364e..4017e80221 100644 --- a/gfx/context/ps3_ctx.c +++ b/gfx/context/ps3_ctx.c @@ -535,6 +535,7 @@ const gfx_ctx_driver_t gfx_ctx_ps3 = { NULL, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "ps3", #ifdef HAVE_RMENU gfx_ctx_set_blend, diff --git a/gfx/context/sdl_ctx.c b/gfx/context/sdl_ctx.c index c52a55354d..49fa2f9bda 100644 --- a/gfx/context/sdl_ctx.c +++ b/gfx/context/sdl_ctx.c @@ -371,6 +371,7 @@ const gfx_ctx_driver_t gfx_ctx_sdl_gl = { gfx_ctx_get_proc_address, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "sdl-gl", }; diff --git a/gfx/context/vc_egl_ctx.c b/gfx/context/vc_egl_ctx.c index 8aeead8d62..c239725a41 100644 --- a/gfx/context/vc_egl_ctx.c +++ b/gfx/context/vc_egl_ctx.c @@ -480,5 +480,6 @@ const gfx_ctx_driver_t gfx_ctx_videocore = { gfx_ctx_get_proc_address, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "videocore", }; diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c index 47f56229d0..3e54e647de 100644 --- a/gfx/context/wgl_ctx.c +++ b/gfx/context/wgl_ctx.c @@ -456,6 +456,7 @@ const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_get_proc_address, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "wgl", }; diff --git a/gfx/context/xdk_ctx.c b/gfx/context/xdk_ctx.c index 269fac0ff2..0f5c37b847 100644 --- a/gfx/context/xdk_ctx.c +++ b/gfx/context/xdk_ctx.c @@ -490,6 +490,7 @@ const gfx_ctx_driver_t gfx_ctx_xdk = { NULL, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "xdk", // RARCH_CONSOLE stuff. diff --git a/gfx/context/xegl_ctx.c b/gfx/context/xegl_ctx.c index 79135d07f5..9cb9bde4cc 100644 --- a/gfx/context/xegl_ctx.c +++ b/gfx/context/xegl_ctx.c @@ -549,6 +549,7 @@ const gfx_ctx_driver_t gfx_ctx_x_egl = { gfx_ctx_get_proc_address, gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, + NULL, "x-egl", }; diff --git a/gfx/gfx_context.h b/gfx/gfx_context.h index b4adfc33cc..20c275417b 100644 --- a/gfx/gfx_context.h +++ b/gfx/gfx_context.h @@ -101,6 +101,10 @@ typedef struct gfx_ctx_driver // Always returns true the first time it's called for a new index. The graphics core must handle a change in the handle correctly. bool (*write_egl_image)(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle); + // Called after frame is rendered, but before swap. + // Can be used to render context-specific overlays and stuff. + bool (*post_render)(void *gl); + // Human readable string. const char *ident; diff --git a/gfx/gl.c b/gfx/gl.c index efcf37abb9..24ddf16b43 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -21,6 +21,7 @@ #include "../driver.h" #include "../performance.h" #include "scaler/scaler.h" +#include "image.h" #include #include "../libretro.h" @@ -1182,6 +1183,9 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei if (msg && gl->font_ctx) gl->font_ctx->render_msg(gl, msg); + if (gl->ctx_driver->post_render) + context_post_render_func(gl); + #if !defined(RARCH_CONSOLE) context_update_window_title_func(false); #endif @@ -1230,6 +1234,8 @@ static void gl_free(void *data) #endif glDeleteTextures(TEXTURES, gl->texture); + if (gl->tex_overlay) + glDeleteTextures(1, &gl->tex_overlay); #if defined(HAVE_PSGL) glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); @@ -1776,9 +1782,78 @@ static void gl_set_aspect_ratio(void *data, unsigned aspectratio_index) gl->keep_aspect = true; gl->should_resize = true; } - #endif +bool gl_load_overlay(gl_t *gl, const char *path) +{ + if (!gl->tex_overlay) + glGenTextures(1, &gl->tex_overlay); + + 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); + + struct texture_image img = {0}; + if (!texture_image_load(path, &img)) + { + RARCH_ERR("Failed to load overlay image: %s.\n", path); + return false; + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(img.width * sizeof(uint32_t))); + glTexImage2D(GL_TEXTURE_2D, 0, RARCH_GL_INTERNAL_FORMAT32, + img.width, img.height, 0, RARCH_GL_TEXTURE_TYPE32, + RARCH_GL_FORMAT32, img.pixels); + + free(img.pixels); + gl_set_overlay_tex_coord(gl, 0, 0, 1, 1); // Default. Stretch to whole screen. + gl_set_overlay_vertex_coord(gl, 0, 0, 1, 1); + return true; +} + +void gl_set_overlay_tex_coord(gl_t *gl, + GLfloat x, GLfloat y, + GLfloat w, GLfloat h) +{ + 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; +} + +void gl_set_overlay_vertex_coord(gl_t *gl, + GLfloat x, GLfloat y, + GLfloat w, GLfloat h) +{ + // 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; +} + +void gl_render_overlay(gl_t *gl) +{ + glBindTexture(GL_TEXTURE_2D, gl->tex_overlay); + + gl_shader_use_func(gl, 0); + glEnable(GL_BLEND); + gl->coords.vertex = gl->overlay_vertex_coord; + gl->coords.tex_coord = gl->overlay_tex_coord; + gl_shader_set_coords_func(gl, &gl->coords, &gl->mvp); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisable(GL_BLEND); + + gl->coords.vertex = vertex_ptr; + gl->coords.tex_coord = gl->tex_coords; +} + const video_driver_t video_gl = { gl_init, gl_frame, diff --git a/gfx/gl_common.h b/gfx/gl_common.h index f09759d372..4cfdba4b89 100644 --- a/gfx/gl_common.h +++ b/gfx/gl_common.h @@ -76,6 +76,7 @@ #define context_translate_aspect_func(width, height) gl->ctx_driver->translate_aspect(width, height) #define context_set_resize_func(width, height) gl->ctx_driver->set_resize(width, height) #define context_swap_buffers_func() gl->ctx_driver->swap_buffers() +#define context_post_render_func(gl) gl->ctx_driver->post_render(gl) #define context_swap_interval_func(var) gl->ctx_driver->swap_interval(var) #define context_has_focus_func() gl->ctx_driver->has_focus() #define context_check_window_func(quit, resize, width, height, frame_count) \ @@ -279,6 +280,12 @@ typedef struct gl bool egl_images; + // Overlay rendering + GLuint tex_overlay; + GLfloat overlay_tex_coord[8]; + GLfloat overlay_vertex_coord[8]; + GLfloat overlay_alpha_mod; // TODO. Needs a specific shader. + #if !defined(HAVE_OPENGLES) && defined(HAVE_FFMPEG) // PBOs used for asynchronous viewport readbacks. GLuint pbo_readback[4]; @@ -359,4 +366,14 @@ void gl_shader_set_coords(gl_t *gl, const struct gl_coords *coords, const math_m void gl_init_fbo(gl_t *gl, unsigned width, unsigned height); void gl_deinit_fbo(gl_t *gl); +bool gl_load_overlay(gl_t *gl, const char *path); +void gl_set_overlay_tex_coord(gl_t *gl, + GLfloat x, GLfloat y, // Relative coordinates [0, 1] range for screen. + GLfloat w, GLfloat h); +void gl_set_overlay_vertex_coord(gl_t *gl, + GLfloat x, GLfloat y, // Relative coordinates [0, 1] range for screen. + GLfloat w, GLfloat h); +void gl_render_overlay(gl_t *gl); + #endif +