mirror of
https://github.com/libretro/RetroArch
synced 2025-03-31 19:21:06 +00:00
Properly implement GPU screenshot for GLES.
Have to use GL_RGBA/GL_UNSIGNED_BYTE as well as reading from back buffer only.
This commit is contained in:
parent
c6ae04ef04
commit
032ba14d3b
79
gfx/gl.c
79
gfx/gl.c
@ -1524,9 +1524,23 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_GL_READ_PIXELS
|
||||||
|
// Screenshots.
|
||||||
|
if (gl->readback_buffer_screenshot)
|
||||||
|
{
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||||
|
#ifndef HAVE_OPENGLES
|
||||||
|
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||||
|
glReadBuffer(GL_BACK);
|
||||||
|
#endif
|
||||||
|
glReadPixels(gl->vp.x, gl->vp.y,
|
||||||
|
gl->vp.width, gl->vp.height,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, gl->readback_buffer_screenshot);
|
||||||
|
}
|
||||||
#if !defined(HAVE_OPENGLES) && defined(HAVE_FFMPEG)
|
#if !defined(HAVE_OPENGLES) && defined(HAVE_FFMPEG)
|
||||||
if (gl->pbo_readback_enable)
|
else if (gl->pbo_readback_enable)
|
||||||
gl_pbo_async_readback(gl);
|
gl_pbo_async_readback(gl);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
context_swap_buffers_func();
|
context_swap_buffers_func();
|
||||||
@ -2369,39 +2383,12 @@ static void gl_viewport_info(void *data, struct rarch_viewport *vp)
|
|||||||
#ifndef NO_GL_READ_PIXELS
|
#ifndef NO_GL_READ_PIXELS
|
||||||
static bool gl_read_viewport(void *data, uint8_t *buffer)
|
static bool gl_read_viewport(void *data, uint8_t *buffer)
|
||||||
{
|
{
|
||||||
unsigned i;
|
|
||||||
gl_t *gl = (gl_t*)data;
|
gl_t *gl = (gl_t*)data;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
(void)i;
|
|
||||||
|
|
||||||
RARCH_PERFORMANCE_INIT(read_viewport);
|
RARCH_PERFORMANCE_INIT(read_viewport);
|
||||||
RARCH_PERFORMANCE_START(read_viewport);
|
RARCH_PERFORMANCE_START(read_viewport);
|
||||||
|
|
||||||
#ifdef HAVE_FBO
|
#if defined(HAVE_FFMPEG) && !defined(HAVE_OPENGLES)
|
||||||
// Make sure we're reading from backbuffer incase some state has been overridden.
|
|
||||||
if (gl->hw_render_fbo_init || gl->fbo_inited)
|
|
||||||
gl_bind_backbuffer();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_OPENGLES
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, get_alignment(gl->vp.width * 3));
|
|
||||||
// GLES doesn't support glReadBuffer ... Take a chance that it'll work out right.
|
|
||||||
glReadPixels(gl->vp.x, gl->vp.y,
|
|
||||||
gl->vp.width, gl->vp.height,
|
|
||||||
GL_RGB, GL_UNSIGNED_BYTE, buffer);
|
|
||||||
|
|
||||||
uint8_t *pixels = (uint8_t*)buffer;
|
|
||||||
unsigned num_pixels = gl->vp.width * gl->vp.height;
|
|
||||||
// Convert RGB to BGR. Formats are byte ordered, so just swap 1st and 3rd byte.
|
|
||||||
for (i = 0; i <= num_pixels; pixels += 3, i++)
|
|
||||||
{
|
|
||||||
uint8_t tmp = pixels[2];
|
|
||||||
pixels[2] = pixels[0];
|
|
||||||
pixels[0] = tmp;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#ifdef HAVE_FFMPEG
|
|
||||||
if (gl->pbo_readback_enable)
|
if (gl->pbo_readback_enable)
|
||||||
{
|
{
|
||||||
if (!gl->pbo_readback_valid) // We haven't buffered up enough frames yet, come back later.
|
if (!gl->pbo_readback_valid) // We haven't buffered up enough frames yet, come back later.
|
||||||
@ -2422,15 +2409,35 @@ static bool gl_read_viewport(void *data, uint8_t *buffer)
|
|||||||
else // Use slow synchronous readbacks. Use this with plain screenshots as we don't really care about performance in this case.
|
else // Use slow synchronous readbacks. Use this with plain screenshots as we don't really care about performance in this case.
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
glPixelStorei(GL_PACK_ROW_LENGTH, gl->vp.width);
|
// GLES2 only guarantees GL_RGBA/GL_UNSIGNED_BYTE readbacks so do just that ...
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, get_alignment(gl->vp.width * 3));
|
// 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.
|
||||||
|
|
||||||
glReadBuffer(GL_FRONT);
|
unsigned num_pixels = gl->vp.width * gl->vp.height;
|
||||||
glReadPixels(gl->vp.x, gl->vp.y,
|
|
||||||
gl->vp.width, gl->vp.height,
|
gl->readback_buffer_screenshot = malloc(num_pixels * sizeof(uint32_t));
|
||||||
GL_BGR, GL_UNSIGNED_BYTE, buffer);
|
if (!gl->readback_buffer_screenshot)
|
||||||
|
{
|
||||||
|
RARCH_PERFORMANCE_STOP(read_viewport);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_frame(gl, NULL, 0, 0, 0, NULL);
|
||||||
|
|
||||||
|
uint8_t *dst = buffer;
|
||||||
|
const uint8_t *src = gl->readback_buffer_screenshot;
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < num_pixels; i++, dst += 3, src += 4)
|
||||||
|
{
|
||||||
|
dst[0] = src[2]; // RGBA -> BGR.
|
||||||
|
dst[1] = src[1];
|
||||||
|
dst[2] = src[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
free(gl->readback_buffer_screenshot);
|
||||||
|
gl->readback_buffer_screenshot = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
RARCH_PERFORMANCE_STOP(read_viewport);
|
RARCH_PERFORMANCE_STOP(read_viewport);
|
||||||
return true;
|
return true;
|
||||||
|
@ -247,6 +247,7 @@ typedef struct gl
|
|||||||
unsigned pbo_readback_index;
|
unsigned pbo_readback_index;
|
||||||
struct scaler_ctx pbo_readback_scaler;
|
struct scaler_ctx pbo_readback_scaler;
|
||||||
#endif
|
#endif
|
||||||
|
void *readback_buffer_screenshot;
|
||||||
|
|
||||||
#if defined(HAVE_MENU)
|
#if defined(HAVE_MENU)
|
||||||
GLuint rgui_texture;
|
GLuint rgui_texture;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user