From 60d96b60b502fe6637f75d2aa0f7d741846042f1 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 12 Nov 2017 17:32:18 +0100 Subject: [PATCH] Start adding gl1_renderchain.c --- gfx/drivers/gl.c | 2 +- gfx/drivers_renderchain/gl1_renderchain.c | 320 ++++++++++++++++++++++ 2 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 gfx/drivers_renderchain/gl1_renderchain.c diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 08134c3c1c..ff81cab58d 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -2162,7 +2162,7 @@ static bool gl_set_shader(void *data, if (textures > gl->textures) /* Have to reinit a bit. */ { - if (gl->hw_render_use && + if (gl->hw_render_use && gl->fbo_inited && gl->renderchain_driver->deinit_hw_render) gl->renderchain_driver->deinit_hw_render(gl); diff --git a/gfx/drivers_renderchain/gl1_renderchain.c b/gfx/drivers_renderchain/gl1_renderchain.c new file mode 100644 index 0000000000..8371942cf7 --- /dev/null +++ b/gfx/drivers_renderchain/gl1_renderchain.c @@ -0,0 +1,320 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2012-2015 - Michael Lelli + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifdef _MSC_VER +#pragma comment(lib, "opengl32") +#endif + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../video_driver.h" +#include "../video_shader_parse.h" +#include "../common/gl_common.h" + +#include "../../driver.h" +#include "../../configuration.h" +#include "../../verbosity.h" + +#if defined(_WIN32) && !defined(_XBOX) +#include "../common/win32_common.h" +#endif + +typedef struct gl1_renderchain +{ + void *empty; +} gl1_renderchain_t; + +#define gl1_bind_fb(id) glBindFramebuffer(RARCH_GL_FRAMEBUFFER, id) + +/* Prototypes */ +static void gl1_renderchain_bind_backbuffer(void) +{ + gl1_bind_fb(0); +} + +void context_bind_hw_render(bool enable); + +GLenum min_filter_to_mag(GLenum type); + +void gl1_renderchain_free(void *data) +{ + gl_t *gl = (gl_t*)data; + (void)gl; +} + +static void gl1_renderchain_bind_prev_texture( + void *data, + const struct video_tex_info *tex_info) +{ + gl_t *gl = (gl_t*)data; + + memmove(gl->prev_info + 1, gl->prev_info, + sizeof(*tex_info) * (gl->textures - 1)); + memcpy(&gl->prev_info[0], tex_info, + sizeof(*tex_info)); +} + +static void gl1_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; +} + +static bool gl1_renderchain_read_viewport( + void *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; + + { + /* 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; +} + +void gl1_renderchain_free_internal(void *data) +{ + gl1_renderchain_t *cg_data = (gl1_renderchain_t*)data; + + if (!cg_data) + return; + + free(cg_data); +} + +static void *gl1_renderchain_new(void) +{ + gl1_renderchain_t *renderchain = (gl1_renderchain_t*)calloc(1, sizeof(*renderchain)); + if (!renderchain) + return NULL; + + return renderchain; +} + +static void gl1_renderchain_ff_vertex(const void *data) +{ + const struct video_coords *coords = (const struct video_coords*)data; + /* Fall back to fixed function-style if needed and possible. */ + glClientActiveTexture(GL_TEXTURE1); + glTexCoordPointer(2, GL_FLOAT, 0, coords->lut_tex_coord); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glVertexPointer(2, GL_FLOAT, 0, coords->vertex); + glEnableClientState(GL_VERTEX_ARRAY); + glColorPointer(4, GL_FLOAT, 0, coords->color); + glEnableClientState(GL_COLOR_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, coords->tex_coord); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +} + +static void gl1_renderchain_ff_matrix(const void *data) +{ + math_matrix_4x4 ident; + const math_matrix_4x4 *mat = (const math_matrix_4x4*)data; + + /* Fall back to fixed function-style if needed and possible. */ + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(mat->data); + glMatrixMode(GL_MODELVIEW); + matrix_4x4_identity(ident); + glLoadMatrixf(ident.data); +} + +static void gl1_renderchain_disable_client_arrays(void) +{ + if (gl_query_core_context_in_use()) + return; + + glClientActiveTexture(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +static void gl1_renderchain_restore_default_state(void *data) +{ + gl_t *gl = (gl_t*)data; + if (!gl) + return; + glEnable(GL_TEXTURE_2D); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_DITHER); +} + +static void gl1_renderchain_copy_frame( + void *data, + video_frame_info_t *video_info, + const void *frame, + unsigned width, unsigned height, unsigned pitch) +{ + gl_t *gl = (gl_t*)data; + const GLvoid *data_buf = frame; + glPixelStorei(GL_UNPACK_ALIGNMENT, video_pixel_get_alignment(pitch)); + + if (gl->base_size == 2 && !gl->have_es2_compat) + { + /* Convert to 32-bit textures on desktop GL. + * + * It is *much* faster (order of magnitude on my setup) + * to use a custom SIMD-optimized conversion routine + * than letting GL do it. */ + video_frame_convert_rgb16_to_rgb32( + &gl->scaler, + gl->conv_buffer, + frame, + width, + height, + pitch); + data_buf = gl->conv_buffer; + } + else + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size); + + glTexSubImage2D(GL_TEXTURE_2D, + 0, 0, 0, width, height, gl->texture_type, + gl->texture_fmt, data_buf); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +} + +static void gl1_renderchain_readback(void *data, + unsigned alignment, + unsigned fmt, unsigned type, + void *src) +{ + gl_t *gl = (gl_t*)data; + + glPixelStorei(GL_PACK_ALIGNMENT, alignment); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glReadBuffer(GL_BACK); + + glReadPixels(gl->vp.x, gl->vp.y, + gl->vp.width, gl->vp.height, + (GLenum)fmt, (GLenum)type, (GLvoid*)src); +} + +gl_renderchain_driver_t gl2_renderchain = { + NULL, /* init_textures_reference */ + NULL, /* fence_iterate */ + NULL, /* fence_free */ + gl1_renderchain_readback, + NULL, /* renderchain_init_pbo */ + NULL, /* renderchain_bind_pbo */ + NULL, /* renderchain_unbind_pbo */ + gl1_renderchain_copy_frame, + gl1_renderchain_restore_default_state, + NULL, /* new_vao */ + NULL, /* free_vao */ + NULL, /* bind_vao */ + NULL, /* unbind_vao */ + gl1_renderchain_disable_client_arrays, /* disable_client_arrays */ + gl1_renderchain_ff_vertex, /* ff_vertex */ + gl1_renderchain_ff_matrix, + gl1_renderchain_bind_backbuffer, + NULL, /* deinit_fbo */ + gl1_renderchain_viewport_info, + gl1_renderchain_read_viewport, + gl1_renderchain_bind_prev_texture, + gl1_renderchain_free_internal, + gl1_renderchain_new, + NULL, /* renderchain_init */ + NULL, /* init_hw_render */ + gl1_renderchain_free, + NULL, /* deinit_hw_render */ + NULL, /* start_render */ + NULL, /* check_fbo_dimensions */ + NULL, /* recompute_pass_sizes */ + NULL, /* renderchain_render */ + "gl1", +};