diff --git a/gfx/common/gl_common.h b/gfx/common/gl_common.h index 90b993f0fe..4cd4e7459a 100644 --- a/gfx/common/gl_common.h +++ b/gfx/common/gl_common.h @@ -204,6 +204,13 @@ struct gl GLuint texture[GFX_MAX_TEXTURES]; GLuint hw_render_fbo[GFX_MAX_TEXTURES]; +#ifdef HAVE_VIDEO_LAYOUT + bool video_layout_resize; + GLuint video_layout_fbo; + GLuint video_layout_fbo_texture; + GLuint video_layout_white_texture; +#endif + unsigned tex_index; /* For use with PREV. */ unsigned textures; unsigned fbo_feedback_pass; diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index d427e75f22..b9ac435481 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -979,7 +979,7 @@ static void gl2_create_fbo_textures(gl_t *gl, glGenTextures(chain->fbo_pass, chain->fbo_texture); for (i = 0; i < chain->fbo_pass; i++) - gl2_create_fbo_texture(gl, + gl2_create_fbo_texture(gl, (gl2_renderchain_data_t*)gl->renderchain_data, i, chain->fbo_texture[i]); @@ -2556,6 +2556,318 @@ static void gl2_pbo_async_readback(gl_t *gl) gl2_renderchain_unbind_pbo(); } +#ifdef HAVE_VIDEO_LAYOUT + +static float video_layout_layer_tex_coord[] = { + 0.0f, 1.0f, + 1.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f, +}; + +static void gl2_video_layout_fbo_init(gl_t *gl, unsigned width, unsigned height) +{ + glGenTextures(1, &gl->video_layout_fbo_texture); + glBindTexture(GL_TEXTURE_2D, gl->video_layout_fbo_texture); + + gl2_load_texture_image(GL_TEXTURE_2D, 0, RARCH_GL_INTERNAL_FORMAT32, + width, height, 0, GL_RGBA, GL_FLOAT, NULL); + + gl2_gen_fb(1, &gl->video_layout_fbo); + gl2_bind_fb(gl->video_layout_fbo); + + gl2_fb_texture_2d(RARCH_GL_FRAMEBUFFER, RARCH_GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, gl->video_layout_fbo_texture, 0); + + if (gl2_check_fb_status(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + RARCH_LOG("Unable to create FBO for video_layout\n"); + + gl2_bind_fb(0); +} + +static void gl2_video_layout_fbo_free(gl_t *gl) +{ + if (gl->video_layout_fbo) + { + gl2_delete_fb(1, &gl->video_layout_fbo); + gl->video_layout_fbo = 0; + } + + if (gl->video_layout_fbo_texture) + { + glDeleteTextures(1, &gl->video_layout_fbo_texture); + gl->video_layout_fbo_texture = 0; + } +} + +static void gl2_video_layout_viewport(gl_t *gl, video_frame_info_t *video_info) +{ + if (!video_layout_valid()) + return; + + if (gl->video_layout_resize) + { + if (gl->video_layout_fbo) + gl2_video_layout_fbo_free(gl); + + gl2_video_layout_fbo_init(gl, video_info->width, video_info->height); + + video_layout_view_change(); + + gl->video_layout_resize = false; + } + + if (video_layout_view_on_change()) + { + video_layout_bounds_t b; + b.x = 0.0f; + b.y = 0.0f; + b.w = (float)video_info->width; + b.h = (float)video_info->height; + video_layout_view_fit_bounds(b); + } + + if (video_layout_screen_count()) + { + const video_layout_bounds_t *bounds; + bounds = video_layout_screen(0); + + glViewport( + bounds->x, video_info->height - bounds->y - bounds->h, + bounds->w, bounds->h + ); + } +} + +static void gl2_video_layout_render(gl_t *gl, video_frame_info_t *video_info) +{ + int i; + + if (!video_layout_valid()) + return; + + glViewport(0, 0, video_info->width, video_info->height); + glEnable(GL_BLEND); + + for (i = 0; i < video_layout_layer_count(); ++i) + video_layout_layer_render(video_info, i); + + glDisable(GL_BLEND); +} + +static void gl2_video_layout_init(gl_t *gl) +{ + uint32_t px; + + gl->video_layout_resize = true; + + /* white 1px texture for drawing solid colors */ + px = 0xFFFFFFFF; + + glGenTextures(1, &gl->video_layout_white_texture); + gl_load_texture_data(gl->video_layout_white_texture, + RARCH_WRAP_EDGE, TEXTURE_FILTER_NEAREST, + sizeof(uint32_t), 1, 1, &px, sizeof(uint32_t)); +} + +static void gl2_video_layout_free(gl_t *gl) +{ + gl2_video_layout_fbo_free(gl); + + if (gl->video_layout_white_texture) + { + glDeleteTextures(1, &gl->video_layout_white_texture); + gl->video_layout_white_texture = 0; + } +} + +static void *gl2_video_layout_take_image(void *video_driver_data, struct texture_image image) +{ + unsigned alignment; + GLuint tex; + + tex = 0; + alignment = video_pixel_get_alignment(image.width * sizeof(uint32_t)); + + glGenTextures(1, &tex); + + gl_load_texture_data(tex, + RARCH_WRAP_EDGE, TEXTURE_FILTER_MIPMAP_LINEAR, + alignment, image.width, image.height, image.pixels, sizeof(uint32_t)); + + free(image.pixels); + + return (void*)(uintptr_t)tex; +} + +static void gl2_video_layout_free_image(void *video_driver_data, void *image) +{ + GLuint tex; + tex = (GLuint)(uintptr_t)image; + glDeleteTextures(1, &tex); +} + +static void gl2_video_layout_layer_begin(const video_layout_render_info_t *info) +{ + gl_t *gl; + gl = (gl_t*)info->video_driver_data; + + gl2_bind_fb(gl->video_layout_fbo); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + gl->shader->use(gl, gl->shader_data, + VIDEO_SHADER_STOCK_BLEND, true); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +static void gl2_video_layout_image(const video_layout_render_info_t *info, void *image_handle, void *alpha_handle) +{ + /* TODO alpha_handle */ + + gl_t *gl; + video_frame_info_t *video_info; + video_layout_bounds_t b; + float coord[8]; + float color[16]; + int i; + + gl = (gl_t*)info->video_driver_data; + video_info = (video_frame_info_t*)info->video_driver_frame_data; + + b = info->bounds; + b.x /= video_info->width; + b.y /= video_info->height; + b.w /= video_info->width; + b.h /= video_info->height; + + coord[0] = b.x; + coord[1] = 1.f - b.y; + coord[2] = b.x + b.w; + coord[3] = 1.f - b.y; + coord[4] = b.x; + coord[5] = 1.f - (b.y + b.h); + coord[6] = b.x + b.w; + coord[7] = 1.f - (b.y + b.h); + + i = 0; + while(i < 16) + { + color[i++] = info->color.r; + color[i++] = info->color.g; + color[i++] = info->color.b; + color[i++] = info->color.a; + } + + gl->coords.vertex = coord; + gl->coords.tex_coord = tex_coords; + gl->coords.color = color; + gl->coords.vertices = 4; + + gl->shader->set_coords(gl->shader_data, &gl->coords); + gl->shader->set_mvp(gl->shader_data, &gl->mvp_no_rot); + + glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr_t)image_handle); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + +static void gl2_video_layout_text(const video_layout_render_info_t *info, const char *str) +{ + /* TODO */ +} + +static void gl2_video_layout_counter(const video_layout_render_info_t *info, int value) +{ + /* TODO */ +} + +static void gl2_video_layout_rect(const video_layout_render_info_t *info) +{ + gl_t *gl; + gl = (gl_t*)info->video_driver_data; + + gl2_video_layout_image(info, (void*)(uintptr_t)gl->video_layout_white_texture, NULL); +} + +static void gl2_video_layout_screen(const video_layout_render_info_t *info, int screen_index) +{ + gl2_video_layout_rect(info); +} + +static void gl2_video_layout_ellipse(const video_layout_render_info_t *info) +{ + /* TODO */ +} + +static void gl2_video_layout_led_dot(const video_layout_render_info_t *info, int dot_count, int dot_mask) +{ + /* TODO */ +} + +static void gl2_video_layout_led_seg(const video_layout_render_info_t *info, video_layout_led_t seg_layout, int seg_mask) +{ + /* TODO */ +} + +static void gl2_video_layout_layer_end(const video_layout_render_info_t *info, video_layout_blend_t blend_type) +{ + gl_t *gl; + gl = (gl_t*)info->video_driver_data; + + switch (blend_type) + { + case VIDEO_LAYOUT_BLEND_ALPHA: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case VIDEO_LAYOUT_BLEND_ADD: + glBlendFunc(GL_ONE, GL_ONE); + break; + case VIDEO_LAYOUT_BLEND_MOD: + glBlendFunc(GL_DST_COLOR, GL_ZERO); + break; + } + + gl2_bind_fb(0); + + gl->coords.vertex = gl->vertex_ptr; + gl->coords.tex_coord = video_layout_layer_tex_coord; + gl->coords.color = gl->white_color_ptr; + gl->coords.vertices = 4; + + gl->shader->set_coords(gl->shader_data, &gl->coords); + gl->shader->set_mvp(gl->shader_data, &gl->mvp_no_rot); + + glBindTexture(GL_TEXTURE_2D, gl->video_layout_fbo_texture); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + gl->coords.tex_coord = gl->tex_info.coord; +} + +static video_layout_render_interface_t gl2_video_layout_render_interface = +{ + gl2_video_layout_take_image, + gl2_video_layout_free_image, + gl2_video_layout_layer_begin, + gl2_video_layout_screen, + gl2_video_layout_image, + gl2_video_layout_text, + gl2_video_layout_counter, + gl2_video_layout_rect, + gl2_video_layout_ellipse, + gl2_video_layout_led_dot, + gl2_video_layout_led_seg, + gl2_video_layout_layer_end +}; + +static const video_layout_render_interface_t *gl2_get_video_layout_render_interface(void *data) +{ + return &gl2_video_layout_render_interface; +} + +#endif /* HAVE_VIDEO_LAYOUT */ + static bool gl2_frame(void *data, const void *frame, unsigned frame_width, unsigned frame_height, uint64_t frame_count, @@ -2617,8 +2929,16 @@ static bool gl2_frame(void *data, const void *frame, } else gl2_set_viewport(gl, video_info, width, height, false, true); + +#ifdef HAVE_VIDEO_LAYOUT + gl->video_layout_resize = true; +#endif } +#ifdef HAVE_VIDEO_LAYOUT + gl2_video_layout_viewport(gl, video_info); +#endif + if (frame) gl->tex_index = ((gl->tex_index + 1) % gl->textures); @@ -2711,7 +3031,7 @@ static bool gl2_frame(void *data, const void *frame, glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if (gl->fbo_inited) - gl2_renderchain_render(gl, + gl2_renderchain_render(gl, chain, video_info, frame_count, &gl->tex_info, &feedback_info); @@ -2720,6 +3040,10 @@ static bool gl2_frame(void *data, const void *frame, gl2_renderchain_bind_prev_texture(gl, chain, &gl->tex_info); +#ifdef HAVE_VIDEO_LAYOUT + gl2_video_layout_render(gl, video_info); +#endif + #if defined(HAVE_MENU) if (gl->menu_texture_enable) { @@ -2858,10 +3182,14 @@ static void gl2_free(void *data) if (!gl) return; +#ifdef HAVE_VIDEO_LAYOUT + gl2_video_layout_free(gl); +#endif + gl2_context_bind_hw_render(gl, false); if (gl->have_sync) - gl2_renderchain_fence_free(gl, + gl2_renderchain_fence_free(gl, (gl2_renderchain_data_t*) gl->renderchain_data); @@ -3598,6 +3926,10 @@ static void *gl2_init(const video_info_t *video, goto error; } +#ifdef HAVE_VIDEO_LAYOUT + gl2_video_layout_init(gl); +#endif + gl2_context_bind_hw_render(gl, true); return gl; @@ -3781,7 +4113,7 @@ static bool gl2_set_shader(void *data, gl2_init_textures_data(gl); if (gl->hw_render_use) - gl2_renderchain_init_hw_render(gl, + gl2_renderchain_init_hw_render(gl, (gl2_renderchain_data_t*)gl->renderchain_data, gl->tex_w, gl->tex_h); } @@ -4235,7 +4567,7 @@ video_driver_t video_gl2 = { gl2_get_overlay_interface, #endif #ifdef HAVE_VIDEO_LAYOUT - NULL, + gl2_get_video_layout_render_interface, #endif gl2_get_poke_interface, gl2_wrap_type_to_enum,