diff --git a/gfx/d3d/d3d.cpp b/gfx/d3d/d3d.cpp index cf4c160937..7274ecaf5a 100644 --- a/gfx/d3d/d3d.cpp +++ b/gfx/d3d/d3d.cpp @@ -1966,6 +1966,7 @@ video_driver_t video_d3d = { d3d_set_rotation, d3d_viewport_info, d3d_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY d3d_get_overlay_interface, #endif diff --git a/gfx/drivers/dispmanx_gfx.c b/gfx/drivers/dispmanx_gfx.c index 52868b1767..f3739bd0de 100644 --- a/gfx/drivers/dispmanx_gfx.c +++ b/gfx/drivers/dispmanx_gfx.c @@ -769,6 +769,7 @@ video_driver_t video_dispmanx = { dispmanx_gfx_set_rotation, dispmanx_gfx_viewport_info, dispmanx_gfx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ diff --git a/gfx/drivers/exynos_gfx.c b/gfx/drivers/exynos_gfx.c index 351e453e01..04236b9bd5 100644 --- a/gfx/drivers/exynos_gfx.c +++ b/gfx/drivers/exynos_gfx.c @@ -1673,6 +1673,7 @@ video_driver_t video_exynos = { exynos_gfx_set_rotation, exynos_gfx_viewport_info, exynos_gfx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index ed1fdb2be2..c7de070afd 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -2760,6 +2760,39 @@ static bool gl_read_viewport(void *data, uint8_t *buffer) } #endif +#if 0 +#define READ_RAW_GL_FRAME_TEST +#endif + +#if defined(READ_RAW_GL_FRAME_TEST) +static void* gl_read_frame_raw(void *data, unsigned *width_p, +unsigned *height_p, size_t *pitch_p) +{ + int i; + gl_t *gl = (gl_t*)data; + unsigned width = gl->last_width[gl->tex_index]; + unsigned height = gl->last_height[gl->tex_index]; + size_t pitch = gl->tex_w * gl->base_size; + void* buffer = malloc(pitch * height); + void* buffer_texture = malloc(pitch * gl->tex_h); + + glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); + glGetTexImage(GL_TEXTURE_2D, 0,gl->texture_type, gl->texture_fmt, buffer_texture); + + for(i = 0; i < height ; i++) + memcpy((uint8_t*)buffer + i * pitch, + (uint8_t*)buffer_texture + (height - 1 - i) * pitch, pitch); + + *width_p = width; + *height_p = height; + *pitch_p = pitch; + + free(buffer_texture); + return buffer; + +} +#endif + #ifdef HAVE_OVERLAY static void gl_free_overlay(gl_t *gl); static bool gl_overlay_load(void *data, @@ -3163,6 +3196,11 @@ video_driver_t video_gl = { gl_viewport_info, gl_read_viewport, +#if defined(READ_RAW_GL_FRAME_TEST) + gl_read_frame_raw, +#else + NULL, +#endif #ifdef HAVE_OVERLAY gl_get_overlay_interface, diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index fc62869839..48dd667470 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -1503,6 +1503,7 @@ video_driver_t video_gx = { gx_set_rotation, gx_viewport_info, gx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY gx_get_overlay_interface, #endif diff --git a/gfx/drivers/nullgfx.c b/gfx/drivers/nullgfx.c index 91b5493e24..78fb9c0d3b 100644 --- a/gfx/drivers/nullgfx.c +++ b/gfx/drivers/nullgfx.c @@ -130,6 +130,7 @@ video_driver_t video_null = { null_gfx_set_rotation, null_gfx_viewport_info, null_gfx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ diff --git a/gfx/drivers/omap_gfx.c b/gfx/drivers/omap_gfx.c index 73a907859f..12245dcced 100644 --- a/gfx/drivers/omap_gfx.c +++ b/gfx/drivers/omap_gfx.c @@ -1171,6 +1171,7 @@ video_driver_t video_omap = { omap_gfx_set_rotation, omap_gfx_viewport_info, omap_gfx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ diff --git a/gfx/drivers/psp1_gfx.c b/gfx/drivers/psp1_gfx.c index da302bcb05..65d0a4262c 100644 --- a/gfx/drivers/psp1_gfx.c +++ b/gfx/drivers/psp1_gfx.c @@ -973,6 +973,7 @@ video_driver_t video_psp1 = { psp_set_rotation, psp_viewport_info, psp_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, #endif diff --git a/gfx/drivers/sdl2_gfx.c b/gfx/drivers/sdl2_gfx.c index c03827dc61..39b21e19e1 100644 --- a/gfx/drivers/sdl2_gfx.c +++ b/gfx/drivers/sdl2_gfx.c @@ -769,6 +769,7 @@ video_driver_t video_sdl2 = { sdl2_gfx_set_rotation, sdl2_gfx_viewport_info, sdl2_gfx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, #endif diff --git a/gfx/drivers/sdl_gfx.c b/gfx/drivers/sdl_gfx.c index 8c177d4577..bdb2e86a6c 100644 --- a/gfx/drivers/sdl_gfx.c +++ b/gfx/drivers/sdl_gfx.c @@ -570,6 +570,7 @@ video_driver_t video_sdl = { sdl_gfx_set_rotation, sdl_gfx_viewport_info, sdl_gfx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, #endif diff --git a/gfx/drivers/sunxi_gfx.c b/gfx/drivers/sunxi_gfx.c index 7364315435..5788052933 100644 --- a/gfx/drivers/sunxi_gfx.c +++ b/gfx/drivers/sunxi_gfx.c @@ -1496,6 +1496,7 @@ video_driver_t video_sunxi = { sunxi_gfx_set_rotation, sunxi_gfx_viewport_info, NULL, /* read_viewport */ + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ diff --git a/gfx/drivers/vg.c b/gfx/drivers/vg.c index 128a67f202..a8a258e1d3 100644 --- a/gfx/drivers/vg.c +++ b/gfx/drivers/vg.c @@ -491,6 +491,7 @@ video_driver_t video_vg = { vg_set_rotation, vg_viewport_info, vg_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ #endif diff --git a/gfx/drivers/xenon360_gfx.c b/gfx/drivers/xenon360_gfx.c index 4e0ca09976..b4fde2e32b 100644 --- a/gfx/drivers/xenon360_gfx.c +++ b/gfx/drivers/xenon360_gfx.c @@ -329,6 +329,7 @@ video_driver_t video_xenon360 = { xenon360_gfx_set_rotation, xenon360_gfx_viewport_info, xenon360_gfx_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ diff --git a/gfx/drivers/xvideo.c b/gfx/drivers/xvideo.c index 3cc9895279..dfa98e78c2 100644 --- a/gfx/drivers/xvideo.c +++ b/gfx/drivers/xvideo.c @@ -937,6 +937,7 @@ video_driver_t video_xvideo = { xv_set_rotation, xv_viewport_info, xv_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ #endif diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 056b174c5f..aff7b59dcf 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -167,6 +167,13 @@ typedef struct video_driver /* Reads out in BGR byte order (24bpp). */ bool (*read_viewport)(void *data, uint8_t *buffer); + /* Returns a pointer to a newly allocated buffer that can + * (and must) be passed to free() by the caller, containing a + * copy of the current raw frame in the active pixel format + * and sets width, height and pitch to the correct values. */ + void* (*read_frame_raw)(void *data, unsigned *width, + unsigned *height, size_t *pitch); + #ifdef HAVE_OVERLAY void (*overlay_interface)(void *data, const video_overlay_interface_t **iface); #endif diff --git a/gfx/video_thread_wrapper.c b/gfx/video_thread_wrapper.c index 31f584c43e..fb7cc8743a 100644 --- a/gfx/video_thread_wrapper.c +++ b/gfx/video_thread_wrapper.c @@ -977,6 +977,7 @@ static const video_driver_t video_thread = { thread_set_rotation, thread_viewport_info, thread_read_viewport, + NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY thread_get_overlay_interface, /* get_overlay_interface */ #endif diff --git a/screenshot.c b/screenshot.c index 93fb86cb14..a7ce5ae52e 100644 --- a/screenshot.c +++ b/screenshot.c @@ -254,9 +254,9 @@ bool take_screenshot(void) return false; viewport_read = (g_settings.video.gpu_screenshot || - g_extern.system.hw_render_callback.context_type - != RETRO_HW_CONTEXT_NONE) && driver.video->read_viewport && - driver.video->viewport_info; + ((g_extern.system.hw_render_callback.context_type + != RETRO_HW_CONTEXT_NONE) && !driver.video->read_frame_raw)) + && driver.video->read_viewport && driver.video->viewport_info; if (viewport_read) { @@ -276,8 +276,32 @@ bool take_screenshot(void) else if (g_extern.frame_cache.data && (g_extern.frame_cache.data != RETRO_HW_FRAME_BUFFER_VALID)) ret = take_screenshot_raw(); - else - RARCH_ERR(RETRO_LOG_TAKE_SCREENSHOT_ERROR); + else if (driver.video->read_frame_raw) + { + const void* old_data = g_extern.frame_cache.data; + unsigned old_width = g_extern.frame_cache.width; + unsigned old_height = g_extern.frame_cache.height; + size_t old_pitch = g_extern.frame_cache.pitch; + + void* frame_data = driver.video->read_frame_raw + (driver.video_data, &g_extern.frame_cache.width, + &g_extern.frame_cache.height, &g_extern.frame_cache.pitch); + + if (frame_data) + { + g_extern.frame_cache.data = frame_data; + ret = take_screenshot_raw(); + free(frame_data); + } + else + RARCH_ERR(RETRO_LOG_TAKE_SCREENSHOT_ERROR); + + g_extern.frame_cache.data = old_data; + g_extern.frame_cache.width = old_width; + g_extern.frame_cache.height = old_height; + g_extern.frame_cache.pitch = old_pitch; + } + if (ret) {