diff --git a/gfx/drivers/d3d.cpp b/gfx/drivers/d3d.cpp index dc83bee411..8fe6ac940d 100644 --- a/gfx/drivers/d3d.cpp +++ b/gfx/drivers/d3d.cpp @@ -1493,7 +1493,7 @@ static bool d3d_read_viewport(void *data, uint8_t *buffer, bool is_idle) !d3d->renderchain_driver->read_viewport) return false; - return d3d->renderchain_driver->read_viewport(d3d, buffer); + return d3d->renderchain_driver->read_viewport(d3d, buffer, false); } static bool d3d_set_shader(void *data, diff --git a/gfx/drivers/d3d_renderchains/render_chain_cg.cpp b/gfx/drivers/d3d_renderchains/render_chain_cg.cpp index bdd7232ce3..f6329b3627 100644 --- a/gfx/drivers/d3d_renderchains/render_chain_cg.cpp +++ b/gfx/drivers/d3d_renderchains/render_chain_cg.cpp @@ -910,9 +910,12 @@ static bool renderchain_set_pass_size(cg_renderchain_t *chain, } static void cg_d3d9_renderchain_convert_geometry( - void *data, const void *info_data, - unsigned *out_width, unsigned *out_height, - unsigned width, unsigned height, + void *data, + const void *info_data, + unsigned *out_width, + unsigned *out_height, + unsigned width, + unsigned height, void *final_viewport_data) { const LinkInfo *info = (const LinkInfo*)info_data; @@ -998,8 +1001,10 @@ static void d3d_recompute_pass_sizes(cg_renderchain_t *chain, } } -static void cg_d3d9_renderchain_set_final_viewport(void *data, - void *renderchain_data, const void *viewport_data) +static void cg_d3d9_renderchain_set_final_viewport( + void *data, + void *renderchain_data, + const void *viewport_data) { d3d_video_t *d3d = (d3d_video_t*)data; cg_renderchain_t *chain = (cg_renderchain_t*)renderchain_data; @@ -1011,7 +1016,9 @@ static void cg_d3d9_renderchain_set_final_viewport(void *data, d3d_recompute_pass_sizes(chain, d3d); } -static bool cg_d3d9_renderchain_add_pass(void *data, const void *info_data) +static bool cg_d3d9_renderchain_add_pass( + void *data, + const void *info_data) { Pass pass; const LinkInfo *info = (const LinkInfo*)info_data; @@ -1482,7 +1489,9 @@ static bool cg_d3d9_renderchain_render( return true; } -static void cg_d3d9_renderchain_set_font_rect(void *data, const void *font_data) +static void cg_d3d9_renderchain_set_font_rect( + void *data, + const void *font_data) { settings_t *settings = config_get_ptr(); d3d_video_t *d3d = (d3d_video_t*)data; @@ -1516,7 +1525,7 @@ static void cg_d3d9_renderchain_set_font_rect(void *data, const void *font_data) d3d->font_rect_shifted.bottom += 2; } -static bool cg_d3d9_renderchain_read_viewport(void *data, uint8_t *buffer) +static bool cg_d3d9_renderchain_read_viewport(void *data, uint8_t *buffer, bool is_idle) { unsigned width, height; D3DLOCKED_RECT rect; diff --git a/gfx/drivers/d3d_renderchains/render_chain_driver.h b/gfx/drivers/d3d_renderchains/render_chain_driver.h index 9bf7bd733b..e5e0eccf18 100644 --- a/gfx/drivers/d3d_renderchains/render_chain_driver.h +++ b/gfx/drivers/d3d_renderchains/render_chain_driver.h @@ -66,7 +66,7 @@ typedef struct renderchain_driver unsigned width, unsigned height, void *final_viewport); void (*set_font_rect)(void *data, const void *param_data); - bool (*read_viewport)(void *data, uint8_t *buffer); + bool (*read_viewport)(void *data, uint8_t *buffer, bool is_idle); void (*viewport_info)(void *data, struct video_viewport *vp); const char *ident; } renderchain_driver_t; diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index cd2cd243c2..32081e098b 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -2338,121 +2338,12 @@ error: static void gl_viewport_info(void *data, struct video_viewport *vp) { - unsigned width, height; - unsigned top_y, top_dist; - gl_t *gl = (gl_t*)data; - - video_driver_get_size(&width, &height); - - *vp = gl->vp; - vp->full_width = width; - vp->full_height = height; - - /* Adjust as GL viewport is bottom-up. */ - top_y = vp->y + vp->height; - top_dist = height - top_y; - vp->y = top_dist; + gl_renderchain_viewport_info(data, vp); } static bool gl_read_viewport(void *data, uint8_t *buffer, bool is_idle) { -#ifndef NO_GL_READ_PIXELS - unsigned num_pixels = 0; - gl_t *gl = (gl_t*)data; - - if (!gl) - return false; - - context_bind_hw_render(false); - - num_pixels = gl->vp.width * gl->vp.height; - -#ifdef HAVE_GL_ASYNC_READBACK - if (gl->pbo_readback_enable) - { - const uint8_t *ptr = NULL; - - /* Don't readback if we're in menu mode. - * We haven't buffered up enough frames yet, come back later. */ - if (!gl->pbo_readback_valid[gl->pbo_readback_index]) - goto error; - - gl->pbo_readback_valid[gl->pbo_readback_index] = false; - glBindBuffer(GL_PIXEL_PACK_BUFFER, - gl->pbo_readback[gl->pbo_readback_index]); - -#ifdef HAVE_OPENGLES3 - /* Slower path, but should work on all implementations at least. */ - ptr = (const uint8_t*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, - 0, num_pixels * sizeof(uint32_t), GL_MAP_READ_BIT); - - if (ptr) - { - unsigned y; - for (y = 0; y < gl->vp.height; y++) - { - video_frame_convert_rgba_to_bgr( - (const void*)ptr, - buffer, - gl->vp.width); - } - } -#else - ptr = (const uint8_t*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); - if (ptr) - { - struct scaler_ctx *ctx = &gl->pbo_readback_scaler; - scaler_ctx_scale_direct(ctx, buffer, ptr); - } -#endif - - if (!ptr) - { - RARCH_ERR("[GL]: Failed to map pixel unpack buffer.\n"); - goto error; - } - - glUnmapBuffer(GL_PIXEL_PACK_BUFFER); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - } - else /* Use slow synchronous readbacks. Use this with plain screenshots - as we don't really care about performance in this case. */ -#endif - { - /* GLES2 only guarantees GL_RGBA/GL_UNSIGNED_BYTE - * readbacks so do just that. - * GLES2 also doesn't support reading back data - * from front buffer, so render a cached frame - * and have gl_frame() do the readback while it's - * in the back buffer. - * - * Keep codepath similar for GLES and desktop GL. - */ - gl->readback_buffer_screenshot = malloc(num_pixels * sizeof(uint32_t)); - - if (!gl->readback_buffer_screenshot) - goto error; - - if (!is_idle) - video_driver_cached_frame(); - - video_frame_convert_rgba_to_bgr( - (const void*)gl->readback_buffer_screenshot, - buffer, - num_pixels); - - free(gl->readback_buffer_screenshot); - gl->readback_buffer_screenshot = NULL; - } - - context_bind_hw_render(true); - return true; - -error: - context_bind_hw_render(true); -#endif - - return false; + return gl_renderchain_read_viewport(data, buffer, is_idle); } #if 0 diff --git a/gfx/drivers/gl_renderchains/render_chain_gl.h b/gfx/drivers/gl_renderchains/render_chain_gl.h index 1cced1e409..381d357f4c 100644 --- a/gfx/drivers/gl_renderchains/render_chain_gl.h +++ b/gfx/drivers/gl_renderchains/render_chain_gl.h @@ -78,6 +78,10 @@ void gl_renderchain_free(gl_t *gl); bool gl_init_hw_render(gl_t *gl, unsigned width, unsigned height); +void gl_renderchain_viewport_info(void *data, struct video_viewport *vp); + +bool gl_renderchain_read_viewport(void *data, uint8_t *buffer, bool is_idle); + void context_bind_hw_render(bool enable); RETRO_END_DECLS diff --git a/gfx/drivers/gl_renderchains/render_chain_gl_legacy.c b/gfx/drivers/gl_renderchains/render_chain_gl_legacy.c index 3a35daa7b3..5ade092b83 100644 --- a/gfx/drivers/gl_renderchains/render_chain_gl_legacy.c +++ b/gfx/drivers/gl_renderchains/render_chain_gl_legacy.c @@ -995,3 +995,122 @@ bool gl_renderchain_add_lut(const struct video_shader *shader, return true; } + +void gl_renderchain_viewport_info(void *data, struct video_viewport *vp) +{ + unsigned width, height; + unsigned top_y, top_dist; + gl_t *gl = (gl_t*)data; + + video_driver_get_size(&width, &height); + + *vp = gl->vp; + vp->full_width = width; + vp->full_height = height; + + /* Adjust as GL viewport is bottom-up. */ + top_y = vp->y + vp->height; + top_dist = height - top_y; + vp->y = top_dist; +} + +bool gl_renderchain_read_viewport(void *data, uint8_t *buffer, bool is_idle) +{ +#ifndef NO_GL_READ_PIXELS + unsigned num_pixels = 0; + gl_t *gl = (gl_t*)data; + + if (!gl) + return false; + + context_bind_hw_render(false); + + num_pixels = gl->vp.width * gl->vp.height; + +#ifdef HAVE_GL_ASYNC_READBACK + if (gl->pbo_readback_enable) + { + const uint8_t *ptr = NULL; + + /* Don't readback if we're in menu mode. + * We haven't buffered up enough frames yet, come back later. */ + if (!gl->pbo_readback_valid[gl->pbo_readback_index]) + goto error; + + gl->pbo_readback_valid[gl->pbo_readback_index] = false; + glBindBuffer(GL_PIXEL_PACK_BUFFER, + gl->pbo_readback[gl->pbo_readback_index]); + +#ifdef HAVE_OPENGLES3 + /* Slower path, but should work on all implementations at least. */ + ptr = (const uint8_t*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, + 0, num_pixels * sizeof(uint32_t), GL_MAP_READ_BIT); + + if (ptr) + { + unsigned y; + for (y = 0; y < gl->vp.height; y++) + { + video_frame_convert_rgba_to_bgr( + (const void*)ptr, + buffer, + gl->vp.width); + } + } +#else + ptr = (const uint8_t*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); + if (ptr) + { + struct scaler_ctx *ctx = &gl->pbo_readback_scaler; + scaler_ctx_scale_direct(ctx, buffer, ptr); + } +#endif + + if (!ptr) + { + RARCH_ERR("[GL]: Failed to map pixel unpack buffer.\n"); + goto error; + } + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + } + else /* Use slow synchronous readbacks. Use this with plain screenshots + as we don't really care about performance in this case. */ +#endif + { + /* GLES2 only guarantees GL_RGBA/GL_UNSIGNED_BYTE + * readbacks so do just that. + * GLES2 also doesn't support reading back data + * from front buffer, so render a cached frame + * and have gl_frame() do the readback while it's + * in the back buffer. + * + * Keep codepath similar for GLES and desktop GL. + */ + gl->readback_buffer_screenshot = malloc(num_pixels * sizeof(uint32_t)); + + if (!gl->readback_buffer_screenshot) + goto error; + + if (!is_idle) + video_driver_cached_frame(); + + video_frame_convert_rgba_to_bgr( + (const void*)gl->readback_buffer_screenshot, + buffer, + num_pixels); + + free(gl->readback_buffer_screenshot); + gl->readback_buffer_screenshot = NULL; + } + + context_bind_hw_render(true); + return true; + +error: + context_bind_hw_render(true); +#endif + + return false; +}