static bool gl1_renderchain_read_viewport( void *data, void *chain_data, uint8_t *buffer, bool is_idle) { unsigned num_pixels = 0; gl_t *gl = (gl_t*)data; if (!gl) return false; num_pixels = gl->vp.width * gl->vp.height; /* Use slow synchronous readbacks. Use this with plain screenshots as we don't really care about performance in this case. */ /* GL1 only guarantees GL_RGBA/GL_UNSIGNED_BYTE * readbacks so do just that. * GL1 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. */ gl->readback_buffer_screenshot = malloc(num_pixels * sizeof(uint32_t)); if (!gl->readback_buffer_screenshot) return false; 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; return true; }
static bool gl1_gfx_read_viewport(void *data, uint8_t *buffer, bool is_idle) { unsigned num_pixels = 0; gl1_t *gl1 = (gl1_t*)data; if (!gl1) return false; gl1_context_bind_hw_render(gl1, false); num_pixels = gl1->vp.width * gl1->vp.height; gl1->readback_buffer_screenshot = malloc(num_pixels * sizeof(uint32_t)); if (!gl1->readback_buffer_screenshot) goto error; if (!is_idle) video_driver_cached_frame(); video_frame_convert_rgba_to_bgr( (const void*)gl1->readback_buffer_screenshot, buffer, num_pixels); free(gl1->readback_buffer_screenshot); gl1->readback_buffer_screenshot = NULL; gl1_context_bind_hw_render(gl1, true); return true; error: gl1_context_bind_hw_render(gl1, true); return false; }
static bool gl2_renderchain_read_viewport( void *data, void *chain_data, uint8_t *buffer, bool is_idle) { 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 #endif { /* Use slow synchronous readbacks. Use this with plain screenshots as we don't really care about performance in this case. */ /* 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); return false; }