2012-04-21 23:13:50 +02:00
/* RetroArch - A frontend for libretro.
2014-01-01 01:50:59 +01:00
* Copyright ( C ) 2010 - 2014 - Hans - Kristian Arntzen
2017-01-22 13:40:32 +01:00
* Copyright ( C ) 2011 - 2017 - Daniel De Matteis
2015-01-07 18:06:50 +01:00
* Copyright ( C ) 2012 - 2015 - Michael Lelli
2016-09-17 20:57:17 -03:00
*
2012-04-21 23:13:50 +02:00
* RetroArch is free software : you can redistribute it and / or modify it under the terms
2010-05-28 18:22:06 +02:00
* 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 .
*
2012-04-21 23:13:50 +02:00
* RetroArch is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ;
2010-05-28 18:22:06 +02:00
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
2012-04-21 23:31:57 +02:00
* You should have received a copy of the GNU General Public License along with RetroArch .
2010-05-28 18:22:06 +02:00
* If not , see < http : //www.gnu.org/licenses/>.
*/
2019-01-10 22:52:13 +01:00
2021-09-26 14:16:09 +02:00
/* Middle of the road OpenGL 2.x driver.
2019-03-18 16:02:28 +01:00
*
2021-09-26 14:16:09 +02:00
* Minimum version ( desktop ) : OpenGL 2.0 + ( 2004 )
* Minimum version ( mobile ) : OpenGLES 2.0 + ( 2007 )
2019-03-18 16:02:28 +01:00
*/
2012-11-14 21:01:40 +01:00
# ifdef _MSC_VER
2019-12-05 17:49:38 +08:00
# if defined(HAVE_OPENGLES)
# pragma comment(lib, "libGLESv2")
# else
2012-11-15 09:40:31 +01:00
# pragma comment(lib, "opengl32")
2012-11-14 21:01:40 +01:00
# endif
2019-12-05 17:49:38 +08:00
# endif
2012-11-14 21:01:40 +01:00
2015-11-09 02:08:40 +01:00
# include <stdint.h>
# include <math.h>
# include <string.h>
2016-09-01 18:10:59 +02:00
# ifdef HAVE_CONFIG_H
2021-08-18 14:19:48 -04:00
# include "../../config.h"
2016-09-01 18:10:59 +02:00
# endif
2015-11-09 02:08:40 +01:00
# include <compat/strl.h>
2014-10-23 04:34:35 +02:00
# include <gfx/scaler/scaler.h>
2015-11-09 05:23:11 +01:00
# include <gfx/math/matrix_4x4.h>
2015-02-22 04:56:18 +01:00
# include <formats/image.h>
2015-03-15 04:37:54 +01:00
# include <retro_inline.h>
2015-11-24 00:05:37 +01:00
# include <retro_miscellaneous.h>
2017-09-28 18:53:09 +02:00
# include <retro_math.h>
2015-12-26 07:59:15 +01:00
# include <string/stdstring.h>
2016-05-10 19:03:53 +02:00
# include <libretro.h>
2015-11-24 00:05:37 +01:00
2016-10-24 04:06:05 +02:00
# include <gfx/gl_capabilities.h>
2016-11-08 15:35:24 +01:00
# include <gfx/video_frame.h>
2017-12-04 05:55:18 +01:00
# include <glsym/glsym.h>
2016-10-24 04:06:05 +02:00
2016-09-05 18:31:32 +02:00
# include "../../configuration.h"
2017-08-07 18:05:43 +02:00
# include "../../dynamic.h"
2011-01-06 18:34:11 +01:00
2015-01-12 06:45:12 +01:00
# include "../../retroarch.h"
2021-11-10 02:34:04 +01:00
# include "../../record/record_driver.h"
2015-12-20 20:52:23 +01:00
# include "../../verbosity.h"
2021-09-26 17:42:12 +02:00
# include "../common/gl2_common.h"
2015-12-20 20:52:23 +01:00
# ifdef HAVE_THREADS
# include "../video_thread_wrapper.h"
# endif
2011-01-07 17:59:53 +01:00
2015-04-03 20:36:19 +02:00
# include "../font_driver.h"
2011-01-06 23:15:49 +01:00
2012-10-16 19:43:05 +02:00
# ifdef HAVE_GLSL
2015-01-12 22:23:48 +01:00
# include "../drivers_shader/shader_glsl.h"
2010-11-12 23:09:43 +01:00
# endif
2010-11-12 22:32:38 +01:00
2014-11-04 18:59:25 +01:00
# ifdef GL_DEBUG
2016-03-20 14:53:54 +01:00
# include <lists/string_list.h>
2016-08-08 18:37:46 +02:00
# if defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2)
# define HAVE_GL_DEBUG_ES
# endif
2014-11-04 18:59:25 +01:00
# endif
2015-12-05 13:22:50 +01:00
# ifdef HAVE_MENU
# include "../../menu/menu_driver.h"
2018-11-22 15:45:52 +01:00
# endif
2020-02-17 21:28:42 +01:00
# ifdef HAVE_GFX_WIDGETS
# include "../gfx_widgets.h"
2015-12-05 13:22:50 +01:00
# endif
2017-11-08 18:54:15 +01:00
# ifndef GL_UNSIGNED_INT_8_8_8_8_REV
# define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
# endif
2020-09-01 19:54:41 +02:00
# define SET_TEXTURE_COORDS(coords, xamt, yamt) \
2017-03-25 10:22:57 +01:00
coords [ 2 ] = xamt ; \
coords [ 6 ] = xamt ; \
coords [ 5 ] = yamt ; \
coords [ 7 ] = yamt
2019-02-06 19:43:31 +01:00
static const shader_backend_t * gl2_shader_ctx_drivers [ ] = {
2019-02-05 01:13:39 +01:00
# ifdef HAVE_GLSL
& gl_glsl_backend ,
# endif
# ifdef HAVE_CG
& gl_cg_backend ,
# endif
NULL
} ;
2017-03-25 10:22:57 +01:00
static struct video_ortho default_ortho = { 0 , 1 , 0 , 1 , - 1 , 1 } ;
2014-10-01 23:50:58 +02:00
/* Used for the last pass when rendering to the back buffer. */
2013-06-30 22:24:07 +02:00
static const GLfloat vertexes_flipped [ ] = {
2012-09-13 17:48:17 +02:00
0 , 1 ,
1 , 1 ,
0 , 0 ,
1 , 0
} ;
2014-10-01 23:50:58 +02:00
/* Used when rendering to an FBO.
2016-09-17 20:57:17 -03:00
* Texture coords have to be aligned
2014-10-01 23:50:58 +02:00
* with vertex coordinates . */
2012-09-13 17:48:17 +02:00
static const GLfloat vertexes [ ] = {
0 , 0 ,
1 , 0 ,
0 , 1 ,
1 , 1
} ;
static const GLfloat tex_coords [ ] = {
2010-11-09 00:13:57 +01:00
0 , 0 ,
2010-11-12 22:32:38 +01:00
1 , 0 ,
2012-09-10 10:29:50 +02:00
0 , 1 ,
2010-11-12 22:32:38 +01:00
1 , 1
2010-11-09 00:13:57 +01:00
} ;
2013-06-30 22:24:07 +02:00
static const GLfloat white_color [ ] = {
1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 ,
} ;
2019-02-06 19:43:31 +01:00
# define gl2_context_bind_hw_render(gl, enable) \
2020-03-07 17:34:35 +01:00
if ( gl - > shared_context_use ) \
2018-10-14 20:04:29 +02:00
gl - > ctx_driver - > bind_hw_render ( gl - > ctx_data , enable )
2019-02-03 00:07:53 +01:00
# define MAX_FENCES 4
# if !defined(HAVE_PSGL)
# ifndef HAVE_GL_SYNC
# define HAVE_GL_SYNC
# endif
# endif
# ifdef HAVE_GL_SYNC
# if defined(HAVE_OPENGLES2)
typedef struct __GLsync * GLsync ;
# endif
# endif
typedef struct gl2_renderchain_data
{
int fbo_pass ;
2020-09-01 19:54:41 +02:00
# ifdef HAVE_GL_SYNC
GLsync fences [ MAX_FENCES ] ;
# endif
2019-02-03 00:07:53 +01:00
GLuint vao ;
GLuint fbo [ GFX_MAX_SHADERS ] ;
GLuint fbo_texture [ GFX_MAX_SHADERS ] ;
GLuint hw_render_depth [ GFX_MAX_TEXTURES ] ;
unsigned fence_count ;
struct gfx_fbo_scale fbo_scale [ GFX_MAX_SHADERS ] ;
2020-09-01 19:54:41 +02:00
bool egl_images ;
bool has_fp_fbo ;
bool has_srgb_fbo_gles3 ;
bool has_srgb_fbo ;
bool hw_render_depth_init ;
2019-02-03 00:07:53 +01:00
} gl2_renderchain_data_t ;
# if (!defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3))
# ifdef GL_PIXEL_PACK_BUFFER
# define HAVE_GL_ASYNC_READBACK
# endif
# endif
# if defined(HAVE_PSGL)
# define gl2_fb_texture_2d(a, b, c, d, e) glFramebufferTexture2DOES(a, b, c, d, e)
# define gl2_check_fb_status(target) glCheckFramebufferStatusOES(target)
# define gl2_gen_fb(n, ids) glGenFramebuffersOES(n, ids)
# define gl2_delete_fb(n, fb) glDeleteFramebuffersOES(n, fb)
# define gl2_bind_fb(id) glBindFramebufferOES(RARCH_GL_FRAMEBUFFER, id)
# define gl2_gen_rb glGenRenderbuffersOES
# define gl2_bind_rb glBindRenderbufferOES
# define gl2_fb_rb glFramebufferRenderbufferOES
# define gl2_rb_storage glRenderbufferStorageOES
# define gl2_delete_rb glDeleteRenderbuffersOES
2022-01-24 16:22:07 +01:00
# elif (defined(__MACH__) && defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < 101200))
2019-02-03 00:07:53 +01:00
# define gl2_fb_texture_2d(a, b, c, d, e) glFramebufferTexture2DEXT(a, b, c, d, e)
# define gl2_check_fb_status(target) glCheckFramebufferStatusEXT(target)
# define gl2_gen_fb(n, ids) glGenFramebuffersEXT(n, ids)
# define gl2_delete_fb(n, fb) glDeleteFramebuffersEXT(n, fb)
# define gl2_bind_fb(id) glBindFramebufferEXT(RARCH_GL_FRAMEBUFFER, id)
# define gl2_gen_rb glGenRenderbuffersEXT
# define gl2_bind_rb glBindRenderbufferEXT
# define gl2_fb_rb glFramebufferRenderbufferEXT
# define gl2_rb_storage glRenderbufferStorageEXT
# define gl2_delete_rb glDeleteRenderbuffersEXT
# else
# define gl2_fb_texture_2d(a, b, c, d, e) glFramebufferTexture2D(a, b, c, d, e)
# define gl2_check_fb_status(target) glCheckFramebufferStatus(target)
# define gl2_gen_fb(n, ids) glGenFramebuffers(n, ids)
# define gl2_delete_fb(n, fb) glDeleteFramebuffers(n, fb)
# define gl2_bind_fb(id) glBindFramebuffer(RARCH_GL_FRAMEBUFFER, id)
# define gl2_gen_rb glGenRenderbuffers
# define gl2_bind_rb glBindRenderbuffer
# define gl2_fb_rb glFramebufferRenderbuffer
# define gl2_rb_storage glRenderbufferStorage
# define gl2_delete_rb glDeleteRenderbuffers
# endif
# ifndef GL_SYNC_GPU_COMMANDS_COMPLETE
# define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
# endif
# ifndef GL_SYNC_FLUSH_COMMANDS_BIT
# define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
# endif
/* Prototypes */
# ifdef IOS
/* There is no default frame buffer on iOS. */
2021-01-18 15:41:30 +01:00
void glkitview_bind_fbo ( void ) ;
# define gl2_renderchain_bind_backbuffer() glkitview_bind_fbo()
2019-02-03 00:07:53 +01:00
# else
# define gl2_renderchain_bind_backbuffer() gl2_bind_fb(0)
# endif
2021-03-11 02:03:37 +01:00
static unsigned gl2_get_alignment ( unsigned pitch )
{
if ( pitch & 1 )
return 1 ;
if ( pitch & 2 )
return 2 ;
if ( pitch & 4 )
return 4 ;
return 8 ;
}
2021-09-26 17:42:12 +02:00
static bool gl2_shader_info ( gl2_t * gl ,
2019-02-05 01:13:39 +01:00
video_shader_ctx_info_t * shader_info )
{
if ( ! shader_info )
return false ;
shader_info - > num = gl - > shader - > num_shaders ( gl - > shader_data ) ;
return true ;
}
2021-09-26 17:42:12 +02:00
static bool gl2_shader_scale ( gl2_t * gl ,
2019-02-05 01:13:39 +01:00
video_shader_ctx_scale_t * scaler )
{
if ( ! scaler | | ! scaler - > scale )
return false ;
scaler - > scale - > valid = false ;
gl - > shader - > shader_scale ( gl - > shader_data ,
scaler - > idx , scaler - > scale ) ;
return true ;
}
2019-02-06 19:43:31 +01:00
static void gl2_size_format ( GLint * internalFormat )
2019-02-03 00:07:53 +01:00
{
# ifndef HAVE_PSGL
switch ( * internalFormat )
{
case GL_RGB :
/* FIXME: PS3 does not support this, neither does it have GL_RGB565_OES. */
* internalFormat = GL_RGB565 ;
break ;
case GL_RGBA :
# ifdef HAVE_OPENGLES2
* internalFormat = GL_RGBA8_OES ;
# else
* internalFormat = GL_RGBA8 ;
# endif
break ;
}
# endif
}
/* This function should only be used without mipmaps
and when data = = NULL */
2019-02-06 19:43:31 +01:00
static void gl2_load_texture_image ( GLenum target ,
2019-02-03 00:07:53 +01:00
GLint level ,
GLint internalFormat ,
GLsizei width ,
GLsizei height ,
GLint border ,
GLenum format ,
GLenum type ,
const GLvoid * data )
{
2021-01-06 19:14:30 +01:00
# if !defined(HAVE_PSGL) && !defined(ORBIS) && !defined(VITA)
2019-02-03 00:07:53 +01:00
# ifdef HAVE_OPENGLES2
2019-04-20 19:55:50 +02:00
enum gl_capability_enum cap = GL_CAPS_TEX_STORAGE_EXT ;
2019-04-03 16:33:16 +02:00
# else
2019-04-20 19:55:50 +02:00
enum gl_capability_enum cap = GL_CAPS_TEX_STORAGE ;
2019-04-03 16:33:16 +02:00
# endif
if ( gl_check_capability ( cap ) & & internalFormat ! = GL_BGRA_EXT )
2019-02-03 00:07:53 +01:00
{
2019-02-06 19:43:31 +01:00
gl2_size_format ( & internalFormat ) ;
2019-04-03 16:33:16 +02:00
# ifdef HAVE_OPENGLES2
2019-02-03 00:07:53 +01:00
glTexStorage2DEXT ( target , 1 , internalFormat , width , height ) ;
# else
2019-04-03 16:33:16 +02:00
glTexStorage2D ( target , 1 , internalFormat , width , height ) ;
2019-02-03 00:07:53 +01:00
# endif
2019-04-03 16:33:16 +02:00
}
2019-02-03 00:07:53 +01:00
else
# endif
{
# ifdef HAVE_OPENGLES
if ( gl_check_capability ( GL_CAPS_GLES3_SUPPORTED ) )
# endif
2019-02-06 19:43:31 +01:00
gl2_size_format ( & internalFormat ) ;
2019-02-03 00:07:53 +01:00
glTexImage2D ( target , level , internalFormat , width ,
height , border , format , type , data ) ;
}
}
2019-02-06 19:43:31 +01:00
static bool gl2_recreate_fbo (
2019-02-03 00:07:53 +01:00
struct video_fbo_rect * fbo_rect ,
GLuint fbo ,
GLuint * texture
)
{
gl2_bind_fb ( fbo ) ;
glDeleteTextures ( 1 , texture ) ;
glGenTextures ( 1 , texture ) ;
glBindTexture ( GL_TEXTURE_2D , * texture ) ;
2019-02-06 19:43:31 +01:00
gl2_load_texture_image ( GL_TEXTURE_2D ,
2019-02-03 00:07:53 +01:00
0 , RARCH_GL_INTERNAL_FORMAT32 ,
fbo_rect - > width ,
fbo_rect - > height ,
0 , RARCH_GL_TEXTURE_TYPE32 ,
RARCH_GL_FORMAT32 , NULL ) ;
gl2_fb_texture_2d ( RARCH_GL_FRAMEBUFFER ,
RARCH_GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D ,
* texture , 0 ) ;
if ( gl2_check_fb_status ( RARCH_GL_FRAMEBUFFER )
= = RARCH_GL_FRAMEBUFFER_COMPLETE )
return true ;
2021-02-18 18:33:47 +02:00
RARCH_WARN ( " [GL]: Failed to reinitialize FBO texture. \n " ) ;
2019-02-03 00:07:53 +01:00
return false ;
}
2021-09-26 17:42:12 +02:00
static void gl2_set_projection ( gl2_t * gl ,
2019-02-03 00:07:53 +01:00
struct video_ortho * ortho , bool allow_rotate )
{
math_matrix_4x4 rot ;
/* Calculate projection. */
matrix_4x4_ortho ( gl - > mvp_no_rot , ortho - > left , ortho - > right ,
ortho - > bottom , ortho - > top , ortho - > znear , ortho - > zfar ) ;
if ( ! allow_rotate )
{
gl - > mvp = gl - > mvp_no_rot ;
return ;
}
matrix_4x4_rotate_z ( rot , M_PI * gl - > rotation / 180.0f ) ;
matrix_4x4_multiply ( gl - > mvp , rot , gl - > mvp_no_rot ) ;
}
2021-09-26 17:42:12 +02:00
static void gl2_set_viewport ( gl2_t * gl ,
2019-02-03 00:07:53 +01:00
unsigned viewport_width ,
unsigned viewport_height ,
bool force_full , bool allow_rotate )
{
2020-03-05 20:29:51 +01:00
settings_t * settings = config_get_ptr ( ) ;
2020-03-05 22:03:58 +01:00
unsigned height = gl - > video_height ;
2019-02-03 00:07:53 +01:00
int x = 0 ;
int y = 0 ;
float device_aspect = ( float ) viewport_width / viewport_height ;
2020-03-05 21:45:02 +01:00
2020-07-27 08:15:35 +02:00
if ( gl - > ctx_driver - > translate_aspect )
device_aspect = gl - > ctx_driver - > translate_aspect (
gl - > ctx_data , viewport_width , viewport_height ) ;
2019-02-03 00:07:53 +01:00
2020-03-05 20:29:51 +01:00
if ( settings - > bools . video_scale_integer & & ! force_full )
2019-02-03 00:07:53 +01:00
{
video_viewport_get_scaled_integer ( & gl - > vp ,
viewport_width , viewport_height ,
video_driver_get_aspect_ratio ( ) , gl - > keep_aspect ) ;
viewport_width = gl - > vp . width ;
viewport_height = gl - > vp . height ;
}
else if ( gl - > keep_aspect & & ! force_full )
{
float desired_aspect = video_driver_get_aspect_ratio ( ) ;
# if defined(HAVE_MENU)
2020-03-05 20:29:51 +01:00
if ( settings - > uints . video_aspect_ratio_idx = = ASPECT_RATIO_CUSTOM )
2019-02-03 00:07:53 +01:00
{
2020-03-05 20:29:51 +01:00
const struct video_viewport * custom = video_viewport_get_custom ( ) ;
2019-02-03 00:07:53 +01:00
/* GL has bottom-left origin viewport. */
2020-03-05 20:29:51 +01:00
x = custom - > x ;
y = height - custom - > y - custom - > height ;
viewport_width = custom - > width ;
viewport_height = custom - > height ;
2019-02-03 00:07:53 +01:00
}
else
# endif
{
float delta ;
if ( fabsf ( device_aspect - desired_aspect ) < 0.0001f )
{
/* If the aspect ratios of screen and desired aspect
* ratio are sufficiently equal ( floating point stuff ) ,
* assume they are actually equal .
*/
}
else if ( device_aspect > desired_aspect )
{
delta = ( desired_aspect / device_aspect - 1.0f ) / 2.0f + 0.5f ;
x = ( int ) roundf ( viewport_width * ( 0.5f - delta ) ) ;
viewport_width = ( unsigned ) roundf ( 2.0f * viewport_width * delta ) ;
}
else
{
delta = ( device_aspect / desired_aspect - 1.0f ) / 2.0f + 0.5f ;
y = ( int ) roundf ( viewport_height * ( 0.5f - delta ) ) ;
viewport_height = ( unsigned ) roundf ( 2.0f * viewport_height * delta ) ;
}
}
gl - > vp . x = x ;
gl - > vp . y = y ;
gl - > vp . width = viewport_width ;
gl - > vp . height = viewport_height ;
}
else
{
gl - > vp . x = gl - > vp . y = 0 ;
gl - > vp . width = viewport_width ;
gl - > vp . height = viewport_height ;
}
# if defined(RARCH_MOBILE)
/* In portrait mode, we want viewport to gravitate to top of screen. */
if ( device_aspect < 1.0f )
gl - > vp . y * = 2 ;
# endif
glViewport ( gl - > vp . x , gl - > vp . y , gl - > vp . width , gl - > vp . height ) ;
2019-02-06 19:43:31 +01:00
gl2_set_projection ( gl , & default_ortho , allow_rotate ) ;
2019-02-03 00:07:53 +01:00
/* Set last backbuffer viewport. */
if ( ! force_full )
{
gl - > vp_out_width = viewport_width ;
gl - > vp_out_height = viewport_height ;
}
#if 0
RARCH_LOG ( " Setting viewport @ %ux%u \n " , viewport_width , viewport_height ) ;
# endif
}
static void gl2_renderchain_render (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
uint64_t frame_count ,
const struct video_tex_info * tex_info ,
const struct video_tex_info * feedback_info )
{
int i ;
video_shader_ctx_params_t params ;
static GLfloat fbo_tex_coords [ 8 ] = { 0.0f } ;
struct video_tex_info fbo_tex_info [ GFX_MAX_SHADERS ] ;
struct video_tex_info * fbo_info = NULL ;
const struct video_fbo_rect * prev_rect = NULL ;
GLfloat xamt = 0.0f ;
GLfloat yamt = 0.0f ;
unsigned mip_level = 0 ;
unsigned fbo_tex_info_cnt = 0 ;
2020-03-07 00:58:06 +01:00
unsigned width = gl - > video_width ;
unsigned height = gl - > video_height ;
2019-02-03 00:07:53 +01:00
/* Render the rest of our passes. */
gl - > coords . tex_coord = fbo_tex_coords ;
/* Calculate viewports, texture coordinates etc,
* and render all passes from FBOs , to another FBO . */
for ( i = 1 ; i < chain - > fbo_pass ; i + + )
{
const struct video_fbo_rect * rect = & gl - > fbo_rect [ i ] ;
prev_rect = & gl - > fbo_rect [ i - 1 ] ;
fbo_info = & fbo_tex_info [ i - 1 ] ;
xamt = ( GLfloat ) prev_rect - > img_width / prev_rect - > width ;
yamt = ( GLfloat ) prev_rect - > img_height / prev_rect - > height ;
2020-09-01 19:54:41 +02:00
SET_TEXTURE_COORDS ( fbo_tex_coords , xamt , yamt ) ;
2019-02-03 00:07:53 +01:00
fbo_info - > tex = chain - > fbo_texture [ i - 1 ] ;
fbo_info - > input_size [ 0 ] = prev_rect - > img_width ;
fbo_info - > input_size [ 1 ] = prev_rect - > img_height ;
fbo_info - > tex_size [ 0 ] = prev_rect - > width ;
fbo_info - > tex_size [ 1 ] = prev_rect - > height ;
memcpy ( fbo_info - > coord , fbo_tex_coords , sizeof ( fbo_tex_coords ) ) ;
fbo_tex_info_cnt + + ;
gl2_bind_fb ( chain - > fbo [ i ] ) ;
2019-02-06 19:49:45 +01:00
gl - > shader - > use ( gl , gl - > shader_data ,
i + 1 , true ) ;
2019-02-03 00:07:53 +01:00
glBindTexture ( GL_TEXTURE_2D , chain - > fbo_texture [ i - 1 ] ) ;
mip_level = i + 1 ;
2019-02-06 19:49:45 +01:00
if ( gl - > shader - > mipmap_input ( gl - > shader_data , mip_level )
2019-02-03 00:07:53 +01:00
& & gl - > have_mipmap )
glGenerateMipmap ( GL_TEXTURE_2D ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
/* Render to FBO with certain size. */
2020-03-05 21:45:02 +01:00
gl2_set_viewport ( gl ,
2019-02-03 00:07:53 +01:00
rect - > img_width , rect - > img_height , true , false ) ;
params . data = gl ;
params . width = prev_rect - > img_width ;
params . height = prev_rect - > img_height ;
params . tex_width = prev_rect - > width ;
params . tex_height = prev_rect - > height ;
params . out_width = gl - > vp . width ;
params . out_height = gl - > vp . height ;
params . frame_counter = ( unsigned int ) frame_count ;
params . info = tex_info ;
params . prev_info = gl - > prev_info ;
params . feedback_info = feedback_info ;
params . fbo_info = fbo_tex_info ;
params . fbo_info_cnt = fbo_tex_info_cnt ;
2019-02-06 19:49:45 +01:00
gl - > shader - > set_params ( & params , gl - > shader_data ) ;
2019-02-03 00:07:53 +01:00
gl - > coords . vertices = 4 ;
2019-03-18 15:27:37 +01:00
gl - > shader - > set_coords ( gl - > shader_data , & gl - > coords ) ;
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp ) ;
2019-02-03 00:07:53 +01:00
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
# if defined(GL_FRAMEBUFFER_SRGB) && !defined(HAVE_OPENGLES)
if ( chain - > has_srgb_fbo )
glDisable ( GL_FRAMEBUFFER_SRGB ) ;
# endif
/* Render our last FBO texture directly to screen. */
prev_rect = & gl - > fbo_rect [ chain - > fbo_pass - 1 ] ;
xamt = ( GLfloat ) prev_rect - > img_width / prev_rect - > width ;
yamt = ( GLfloat ) prev_rect - > img_height / prev_rect - > height ;
2020-09-01 19:54:41 +02:00
SET_TEXTURE_COORDS ( fbo_tex_coords , xamt , yamt ) ;
2019-02-03 00:07:53 +01:00
/* Push final FBO to list. */
fbo_info = & fbo_tex_info [ chain - > fbo_pass - 1 ] ;
fbo_info - > tex = chain - > fbo_texture [ chain - > fbo_pass - 1 ] ;
fbo_info - > input_size [ 0 ] = prev_rect - > img_width ;
fbo_info - > input_size [ 1 ] = prev_rect - > img_height ;
fbo_info - > tex_size [ 0 ] = prev_rect - > width ;
fbo_info - > tex_size [ 1 ] = prev_rect - > height ;
memcpy ( fbo_info - > coord , fbo_tex_coords , sizeof ( fbo_tex_coords ) ) ;
fbo_tex_info_cnt + + ;
/* Render our FBO texture to back buffer. */
gl2_renderchain_bind_backbuffer ( ) ;
2019-02-06 19:49:45 +01:00
gl - > shader - > use ( gl , gl - > shader_data ,
chain - > fbo_pass + 1 , true ) ;
2019-02-03 00:07:53 +01:00
glBindTexture ( GL_TEXTURE_2D , chain - > fbo_texture [ chain - > fbo_pass - 1 ] ) ;
mip_level = chain - > fbo_pass + 1 ;
2019-02-03 04:47:52 +01:00
if (
2019-02-06 19:49:45 +01:00
gl - > shader - > mipmap_input ( gl - > shader_data , mip_level ) & &
gl - > have_mipmap )
2019-02-03 00:07:53 +01:00
glGenerateMipmap ( GL_TEXTURE_2D ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
2020-03-05 21:45:02 +01:00
gl2_set_viewport ( gl ,
2019-02-03 00:07:53 +01:00
width , height , false , true ) ;
params . data = gl ;
params . width = prev_rect - > img_width ;
params . height = prev_rect - > img_height ;
params . tex_width = prev_rect - > width ;
params . tex_height = prev_rect - > height ;
params . out_width = gl - > vp . width ;
params . out_height = gl - > vp . height ;
params . frame_counter = ( unsigned int ) frame_count ;
params . info = tex_info ;
params . prev_info = gl - > prev_info ;
params . feedback_info = feedback_info ;
params . fbo_info = fbo_tex_info ;
params . fbo_info_cnt = fbo_tex_info_cnt ;
2019-02-06 19:49:45 +01:00
gl - > shader - > set_params ( & params , gl - > shader_data ) ;
2019-02-03 00:07:53 +01:00
gl - > coords . vertex = gl - > vertex_ptr ;
gl - > coords . vertices = 4 ;
2019-03-18 15:27:37 +01:00
gl - > shader - > set_coords ( gl - > shader_data , & gl - > coords ) ;
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp ) ;
2019-02-03 00:07:53 +01:00
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
gl - > coords . tex_coord = gl - > tex_info . coord ;
}
2021-09-26 17:42:12 +02:00
static void gl2_renderchain_deinit_fbo ( gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain )
{
if ( gl )
{
if ( gl - > fbo_feedback )
gl2_delete_fb ( 1 , & gl - > fbo_feedback ) ;
if ( gl - > fbo_feedback_texture )
glDeleteTextures ( 1 , & gl - > fbo_feedback_texture ) ;
gl - > fbo_inited = false ;
gl - > fbo_feedback_enable = false ;
gl - > fbo_feedback_pass = 0 ;
gl - > fbo_feedback_texture = 0 ;
gl - > fbo_feedback = 0 ;
}
if ( chain )
{
gl2_delete_fb ( chain - > fbo_pass , chain - > fbo ) ;
glDeleteTextures ( chain - > fbo_pass , chain - > fbo_texture ) ;
memset ( chain - > fbo_texture , 0 , sizeof ( chain - > fbo_texture ) ) ;
memset ( chain - > fbo , 0 , sizeof ( chain - > fbo ) ) ;
chain - > fbo_pass = 0 ;
}
}
static void gl2_renderchain_deinit_hw_render (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain )
{
if ( ! gl )
return ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2019-02-03 00:07:53 +01:00
if ( gl - > hw_render_fbo_init )
gl2_delete_fb ( gl - > textures , gl - > hw_render_fbo ) ;
if ( chain - > hw_render_depth_init )
gl2_delete_rb ( gl - > textures , chain - > hw_render_depth ) ;
gl - > hw_render_fbo_init = false ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2019-02-03 00:07:53 +01:00
}
2021-09-26 17:42:12 +02:00
static bool gl2_create_fbo_targets ( gl2_t * gl , gl2_renderchain_data_t * chain )
2019-02-03 00:07:53 +01:00
{
unsigned i ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
gl2_gen_fb ( chain - > fbo_pass , chain - > fbo ) ;
2019-02-04 23:17:39 +01:00
for ( i = 0 ; i < ( unsigned ) chain - > fbo_pass ; i + + )
2019-02-03 00:07:53 +01:00
{
GLenum status ;
gl2_bind_fb ( chain - > fbo [ i ] ) ;
gl2_fb_texture_2d ( RARCH_GL_FRAMEBUFFER ,
RARCH_GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , chain - > fbo_texture [ i ] , 0 ) ;
status = gl2_check_fb_status ( RARCH_GL_FRAMEBUFFER ) ;
if ( status ! = RARCH_GL_FRAMEBUFFER_COMPLETE )
goto error ;
}
if ( gl - > fbo_feedback_texture )
{
GLenum status ;
gl2_gen_fb ( 1 , & gl - > fbo_feedback ) ;
gl2_bind_fb ( gl - > fbo_feedback ) ;
gl2_fb_texture_2d ( RARCH_GL_FRAMEBUFFER ,
RARCH_GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D ,
gl - > fbo_feedback_texture , 0 ) ;
status = gl2_check_fb_status ( RARCH_GL_FRAMEBUFFER ) ;
if ( status ! = RARCH_GL_FRAMEBUFFER_COMPLETE )
goto error ;
/* Make sure the feedback textures are cleared
* so we don ' t feedback noise . */
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
}
return true ;
error :
gl2_delete_fb ( chain - > fbo_pass , chain - > fbo ) ;
if ( gl - > fbo_feedback )
gl2_delete_fb ( 1 , & gl - > fbo_feedback ) ;
RARCH_ERR ( " [GL]: Failed to set up frame buffer objects. Multi-pass shading will not work. \n " ) ;
return false ;
}
2019-02-06 19:43:31 +01:00
static unsigned gl2_wrap_type_to_enum ( enum gfx_wrap_type type )
2019-02-03 00:11:41 +01:00
{
switch ( type )
{
# ifndef HAVE_OPENGLES
case RARCH_WRAP_BORDER : /* GL_CLAMP_TO_BORDER: Available since GL 1.3 */
return GL_CLAMP_TO_BORDER ;
# else
case RARCH_WRAP_BORDER :
# endif
case RARCH_WRAP_EDGE :
return GL_CLAMP_TO_EDGE ;
case RARCH_WRAP_REPEAT :
return GL_REPEAT ;
case RARCH_WRAP_MIRRORED_REPEAT :
return GL_MIRRORED_REPEAT ;
default :
break ;
}
return 0 ;
}
2019-02-06 19:43:31 +01:00
static GLenum gl2_min_filter_to_mag ( GLenum type )
2019-02-03 00:11:41 +01:00
{
switch ( type )
{
case GL_LINEAR_MIPMAP_LINEAR :
return GL_LINEAR ;
case GL_NEAREST_MIPMAP_NEAREST :
return GL_NEAREST ;
default :
break ;
}
return type ;
}
2021-09-26 17:42:12 +02:00
static void gl2_create_fbo_texture ( gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
unsigned i , GLuint texture )
{
GLenum mag_filter , wrap_enum ;
2019-02-03 05:41:43 +01:00
enum gfx_wrap_type wrap_type ;
2019-02-03 00:07:53 +01:00
bool fp_fbo = false ;
bool smooth = false ;
settings_t * settings = config_get_ptr ( ) ;
2020-02-13 23:24:51 +01:00
bool video_smooth = settings - > bools . video_smooth ;
2020-03-04 23:36:22 -05:00
# if HAVE_ODROIDGO2
2020-04-01 20:41:38 +02:00
bool video_ctx_scaling = settings - > bools . video_ctx_scaling ;
2020-03-04 23:36:22 -05:00
if ( video_ctx_scaling )
video_smooth = false ;
# endif
2020-07-23 06:50:08 +02:00
# ifndef HAVE_OPENGLES
2020-02-18 14:51:40 +01:00
bool force_srgb_disable = settings - > bools . video_force_srgb_disable ;
2020-07-23 06:50:08 +02:00
# endif
2020-02-13 23:24:51 +01:00
GLuint base_filt = video_smooth ? GL_LINEAR : GL_NEAREST ;
GLuint base_mip_filt = video_smooth ?
2019-02-03 00:07:53 +01:00
GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST ;
unsigned mip_level = i + 2 ;
2019-02-03 04:47:52 +01:00
bool mipmapped = gl - > shader - > mipmap_input ( gl - > shader_data , mip_level ) ;
2019-02-03 00:07:53 +01:00
GLenum min_filter = mipmapped ? base_mip_filt : base_filt ;
2019-02-03 05:28:00 +01:00
if ( gl - > shader - > filter_type ( gl - > shader_data ,
2019-02-03 05:32:03 +01:00
i + 2 , & smooth ) )
2019-02-03 00:07:53 +01:00
{
min_filter = mipmapped ? ( smooth ?
GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST )
: ( smooth ? GL_LINEAR : GL_NEAREST ) ;
}
2019-02-06 19:43:31 +01:00
mag_filter = gl2_min_filter_to_mag ( min_filter ) ;
2019-02-03 00:07:53 +01:00
2019-02-03 05:41:43 +01:00
wrap_type = gl - > shader - > wrap_type ( gl - > shader_data , i + 2 ) ;
2019-02-03 00:07:53 +01:00
2019-02-06 19:43:31 +01:00
wrap_enum = gl2_wrap_type_to_enum ( wrap_type ) ;
2019-02-03 00:07:53 +01:00
2021-09-26 17:42:12 +02:00
GL2_BIND_TEXTURE ( texture , wrap_enum , mag_filter , min_filter ) ;
2019-02-03 00:07:53 +01:00
fp_fbo = chain - > fbo_scale [ i ] . fp_fbo ;
if ( fp_fbo )
{
if ( ! chain - > has_fp_fbo )
RARCH_ERR ( " [GL]: Floating-point FBO was requested, but is not supported. Falling back to UNORM. Result may band/clip/etc.! \n " ) ;
}
# if !defined(HAVE_OPENGLES2)
if ( fp_fbo & & chain - > has_fp_fbo )
{
RARCH_LOG ( " [GL]: FBO pass #%d is floating-point. \n " , i ) ;
2019-02-06 19:43:31 +01:00
gl2_load_texture_image ( GL_TEXTURE_2D , 0 , GL_RGBA32F ,
2019-02-03 00:07:53 +01:00
gl - > fbo_rect [ i ] . width , gl - > fbo_rect [ i ] . height ,
0 , GL_RGBA , GL_FLOAT , NULL ) ;
}
else
# endif
{
# ifndef HAVE_OPENGLES
bool srgb_fbo = chain - > fbo_scale [ i ] . srgb_fbo ;
if ( ! fp_fbo & & srgb_fbo )
{
if ( ! chain - > has_srgb_fbo )
RARCH_ERR ( " [GL]: sRGB FBO was requested, but it is not supported. Falling back to UNORM. Result may have banding! \n " ) ;
}
2020-02-18 14:51:40 +01:00
if ( force_srgb_disable )
2019-02-03 00:07:53 +01:00
srgb_fbo = false ;
if ( srgb_fbo & & chain - > has_srgb_fbo )
{
RARCH_LOG ( " [GL]: FBO pass #%d is sRGB. \n " , i ) ;
# ifdef HAVE_OPENGLES2
/* EXT defines are same as core GLES3 defines,
* but GLES3 variant requires different arguments . */
glTexImage2D ( GL_TEXTURE_2D ,
0 , GL_SRGB_ALPHA_EXT ,
gl - > fbo_rect [ i ] . width , gl - > fbo_rect [ i ] . height , 0 ,
chain - > has_srgb_fbo_gles3 ? GL_RGBA : GL_SRGB_ALPHA_EXT ,
GL_UNSIGNED_BYTE , NULL ) ;
# else
2019-02-06 19:43:31 +01:00
gl2_load_texture_image ( GL_TEXTURE_2D ,
2019-02-03 00:07:53 +01:00
0 , GL_SRGB8_ALPHA8 ,
gl - > fbo_rect [ i ] . width , gl - > fbo_rect [ i ] . height , 0 ,
GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
# endif
}
else
# endif
{
2020-12-11 18:22:27 +01:00
# if defined(HAVE_OPENGLES2)
2019-02-03 00:07:53 +01:00
glTexImage2D ( GL_TEXTURE_2D ,
0 , GL_RGBA ,
gl - > fbo_rect [ i ] . width , gl - > fbo_rect [ i ] . height , 0 ,
GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
2020-12-11 18:22:27 +01:00
# elif defined(HAVE_PSGL)
glTexImage2D ( GL_TEXTURE_2D ,
0 , GL_ARGB_SCE ,
gl - > fbo_rect [ i ] . width , gl - > fbo_rect [ i ] . height , 0 ,
GL_ARGB_SCE , GL_UNSIGNED_BYTE , NULL ) ;
2019-02-03 00:07:53 +01:00
# else
/* Avoid potential performance
* reductions on particular platforms . */
2019-02-06 19:43:31 +01:00
gl2_load_texture_image ( GL_TEXTURE_2D ,
2019-02-03 00:07:53 +01:00
0 , RARCH_GL_INTERNAL_FORMAT32 ,
gl - > fbo_rect [ i ] . width , gl - > fbo_rect [ i ] . height , 0 ,
RARCH_GL_TEXTURE_TYPE32 , RARCH_GL_FORMAT32 , NULL ) ;
# endif
}
}
}
2021-09-26 17:42:12 +02:00
static void gl2_create_fbo_textures ( gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain )
{
int i ;
glGenTextures ( chain - > fbo_pass , chain - > fbo_texture ) ;
for ( i = 0 ; i < chain - > fbo_pass ; i + + )
2019-04-03 05:04:17 +01:00
gl2_create_fbo_texture ( gl ,
2019-02-07 23:16:25 +01:00
( gl2_renderchain_data_t * ) gl - > renderchain_data ,
2019-02-03 00:07:53 +01:00
i , chain - > fbo_texture [ i ] ) ;
if ( gl - > fbo_feedback_enable )
{
glGenTextures ( 1 , & gl - > fbo_feedback_texture ) ;
2019-02-06 19:43:31 +01:00
gl2_create_fbo_texture ( gl ,
2019-02-07 23:16:25 +01:00
( gl2_renderchain_data_t * ) gl - > renderchain_data ,
2019-02-03 00:07:53 +01:00
gl - > fbo_feedback_pass , gl - > fbo_feedback_texture ) ;
}
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
/* Compute FBO geometry.
* When width / height changes or window sizes change ,
* we have to recalculate geometry of our FBO . */
static void gl2_renderchain_recompute_pass_sizes (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
unsigned width , unsigned height ,
unsigned vp_width , unsigned vp_height )
{
unsigned i ;
bool size_modified = false ;
GLint max_size = 0 ;
unsigned last_width = width ;
unsigned last_height = height ;
unsigned last_max_width = gl - > tex_w ;
unsigned last_max_height = gl - > tex_h ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & max_size ) ;
/* Calculate viewports for FBOs. */
2019-02-04 23:17:39 +01:00
for ( i = 0 ; i < ( unsigned ) chain - > fbo_pass ; i + + )
2019-02-03 00:07:53 +01:00
{
struct video_fbo_rect * fbo_rect = & gl - > fbo_rect [ i ] ;
struct gfx_fbo_scale * fbo_scale = & chain - > fbo_scale [ i ] ;
2019-08-14 16:40:47 +02:00
switch ( fbo_scale - > type_x )
{
case RARCH_SCALE_INPUT :
fbo_rect - > img_width = fbo_scale - > scale_x * last_width ;
fbo_rect - > max_img_width = last_max_width * fbo_scale - > scale_x ;
break ;
case RARCH_SCALE_ABSOLUTE :
fbo_rect - > img_width = fbo_rect - > max_img_width =
fbo_scale - > abs_x ;
break ;
case RARCH_SCALE_VIEWPORT :
2019-11-16 19:52:47 +01:00
if ( gl - > rotation % 180 = = 90 )
{
fbo_rect - > img_width = fbo_rect - > max_img_width =
fbo_scale - > scale_x * vp_height ;
} else {
fbo_rect - > img_width = fbo_rect - > max_img_width =
2019-08-14 16:40:47 +02:00
fbo_scale - > scale_x * vp_width ;
2019-11-16 19:52:47 +01:00
}
2019-08-14 16:40:47 +02:00
break ;
}
switch ( fbo_scale - > type_y )
{
case RARCH_SCALE_INPUT :
fbo_rect - > img_height = last_height * fbo_scale - > scale_y ;
fbo_rect - > max_img_height = last_max_height * fbo_scale - > scale_y ;
break ;
case RARCH_SCALE_ABSOLUTE :
fbo_rect - > img_height = fbo_scale - > abs_y ;
fbo_rect - > max_img_height = fbo_scale - > abs_y ;
break ;
case RARCH_SCALE_VIEWPORT :
2019-11-16 19:52:47 +01:00
if ( gl - > rotation % 180 = = 90 )
{
fbo_rect - > img_height = fbo_rect - > max_img_height =
fbo_scale - > scale_y * vp_width ;
} else {
2019-08-14 16:40:47 +02:00
fbo_rect - > img_height = fbo_rect - > max_img_height =
fbo_scale - > scale_y * vp_height ;
2019-11-16 19:52:47 +01:00
}
2019-08-14 16:40:47 +02:00
break ;
}
2019-02-03 00:07:53 +01:00
if ( fbo_rect - > img_width > ( unsigned ) max_size )
{
size_modified = true ;
fbo_rect - > img_width = max_size ;
}
if ( fbo_rect - > img_height > ( unsigned ) max_size )
{
size_modified = true ;
fbo_rect - > img_height = max_size ;
}
if ( fbo_rect - > max_img_width > ( unsigned ) max_size )
{
size_modified = true ;
fbo_rect - > max_img_width = max_size ;
}
if ( fbo_rect - > max_img_height > ( unsigned ) max_size )
{
size_modified = true ;
fbo_rect - > max_img_height = max_size ;
}
if ( size_modified )
2021-02-18 18:33:47 +02:00
RARCH_WARN ( " [GL]: FBO textures exceeded maximum size of GPU (%dx%d). Resizing to fit. \n " , max_size , max_size ) ;
2019-02-03 00:07:53 +01:00
last_width = fbo_rect - > img_width ;
last_height = fbo_rect - > img_height ;
last_max_width = fbo_rect - > max_img_width ;
last_max_height = fbo_rect - > max_img_height ;
}
}
static void gl2_renderchain_start_render (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2020-03-07 00:58:06 +01:00
gl2_renderchain_data_t * chain )
2019-02-03 00:07:53 +01:00
{
/* Used when rendering to an FBO.
* Texture coords have to be aligned
* with vertex coordinates . */
static const GLfloat fbo_vertexes [ ] = {
0 , 0 ,
1 , 0 ,
0 , 1 ,
1 , 1
} ;
glBindTexture ( GL_TEXTURE_2D , gl - > texture [ gl - > tex_index ] ) ;
gl2_bind_fb ( chain - > fbo [ 0 ] ) ;
2019-02-06 19:43:31 +01:00
gl2_set_viewport ( gl ,
2020-03-05 21:45:02 +01:00
gl - > fbo_rect [ 0 ] . img_width ,
2019-02-03 00:07:53 +01:00
gl - > fbo_rect [ 0 ] . img_height , true , false ) ;
/* Need to preserve the "flipped" state when in FBO
* as well to have consistent texture coordinates .
*
* We will " flip " it in place on last pass . */
gl - > coords . vertex = fbo_vertexes ;
# if defined(GL_FRAMEBUFFER_SRGB) && !defined(HAVE_OPENGLES)
if ( chain - > has_srgb_fbo )
glEnable ( GL_FRAMEBUFFER_SRGB ) ;
# endif
}
/* Set up render to texture. */
2019-02-03 00:13:41 +01:00
static void gl2_renderchain_init (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
unsigned fbo_width , unsigned fbo_height )
{
int i ;
unsigned width , height ;
video_shader_ctx_scale_t scaler ;
video_shader_ctx_info_t shader_info ;
struct gfx_fbo_scale scale , scale_last ;
2019-02-06 19:43:31 +01:00
if ( ! gl2_shader_info ( gl , & shader_info ) )
2019-02-03 19:40:27 +01:00
return ;
2019-02-03 00:07:53 +01:00
2019-02-03 19:40:27 +01:00
if ( ! gl | | shader_info . num = = 0 )
2019-02-03 00:07:53 +01:00
return ;
2019-08-13 12:14:33 +02:00
width = gl - > video_width ;
height = gl - > video_height ;
2019-02-03 00:07:53 +01:00
2019-02-03 19:40:36 +01:00
scaler . idx = 1 ;
scaler . scale = & scale ;
2019-02-03 00:07:53 +01:00
2019-02-06 19:43:31 +01:00
gl2_shader_scale ( gl , & scaler ) ;
2019-02-03 00:07:53 +01:00
2019-02-03 19:40:36 +01:00
scaler . idx = shader_info . num ;
scaler . scale = & scale_last ;
2019-02-03 00:07:53 +01:00
2019-02-06 19:43:31 +01:00
gl2_shader_scale ( gl , & scaler ) ;
2019-02-03 00:07:53 +01:00
2019-02-03 19:40:36 +01:00
/* we always want FBO to be at least initialized on startup for consoles */
2019-02-03 00:07:53 +01:00
if ( shader_info . num = = 1 & & ! scale . valid )
return ;
if ( ! gl - > has_fbo )
{
RARCH_ERR ( " [GL]: Failed to locate FBO functions. Won't be able to use render-to-texture. \n " ) ;
return ;
}
chain - > fbo_pass = shader_info . num - 1 ;
if ( scale_last . valid )
chain - > fbo_pass + + ;
if ( ! scale . valid )
{
scale . scale_x = 1.0f ;
scale . scale_y = 1.0f ;
scale . type_x = scale . type_y = RARCH_SCALE_INPUT ;
scale . valid = true ;
}
chain - > fbo_scale [ 0 ] = scale ;
for ( i = 1 ; i < chain - > fbo_pass ; i + + )
{
2019-02-03 19:40:36 +01:00
scaler . idx = i + 1 ;
scaler . scale = & chain - > fbo_scale [ i ] ;
2019-02-03 00:07:53 +01:00
2019-02-06 19:43:31 +01:00
gl2_shader_scale ( gl , & scaler ) ;
2019-02-03 00:07:53 +01:00
if ( ! chain - > fbo_scale [ i ] . valid )
{
chain - > fbo_scale [ i ] . scale_x = chain - > fbo_scale [ i ] . scale_y = 1.0f ;
chain - > fbo_scale [ i ] . type_x = chain - > fbo_scale [ i ] . type_y =
RARCH_SCALE_INPUT ;
chain - > fbo_scale [ i ] . valid = true ;
}
}
gl2_renderchain_recompute_pass_sizes ( gl ,
chain , fbo_width , fbo_height , width , height ) ;
for ( i = 0 ; i < chain - > fbo_pass ; i + + )
{
gl - > fbo_rect [ i ] . width = next_pow2 ( gl - > fbo_rect [ i ] . img_width ) ;
gl - > fbo_rect [ i ] . height = next_pow2 ( gl - > fbo_rect [ i ] . img_height ) ;
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " [GL]: Creating FBO %d @ %ux%u. \n " , i ,
2019-02-03 00:07:53 +01:00
gl - > fbo_rect [ i ] . width , gl - > fbo_rect [ i ] . height ) ;
}
2019-02-03 05:05:23 +01:00
gl - > fbo_feedback_enable = gl - > shader - > get_feedback_pass ( gl - > shader_data ,
2019-02-03 00:07:53 +01:00
& gl - > fbo_feedback_pass ) ;
if ( gl - > fbo_feedback_enable & & gl - > fbo_feedback_pass
< ( unsigned ) chain - > fbo_pass )
{
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " [GL]: Creating feedback FBO %d @ %ux%u. \n " , i ,
2019-02-03 00:07:53 +01:00
gl - > fbo_rect [ gl - > fbo_feedback_pass ] . width ,
gl - > fbo_rect [ gl - > fbo_feedback_pass ] . height ) ;
}
else if ( gl - > fbo_feedback_enable )
{
RARCH_WARN ( " [GL]: Tried to create feedback FBO of pass #%u, but there are only %d FBO passes. Will use input texture as feedback texture. \n " ,
gl - > fbo_feedback_pass , chain - > fbo_pass ) ;
gl - > fbo_feedback_enable = false ;
}
2019-02-06 19:43:31 +01:00
gl2_create_fbo_textures ( gl , chain ) ;
if ( ! gl | | ! gl2_create_fbo_targets ( gl , chain ) )
2019-02-03 00:07:53 +01:00
{
glDeleteTextures ( chain - > fbo_pass , chain - > fbo_texture ) ;
RARCH_ERR ( " [GL]: Failed to create FBO targets. Will continue without FBO. \n " ) ;
return ;
}
gl - > fbo_inited = true ;
}
static bool gl2_renderchain_init_hw_render (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
unsigned width , unsigned height )
{
GLenum status ;
unsigned i ;
bool depth = false ;
bool stencil = false ;
GLint max_fbo_size = 0 ;
GLint max_renderbuffer_size = 0 ;
struct retro_hw_render_callback * hwr =
video_driver_get_hw_context ( ) ;
/* We can only share texture objects through contexts.
* FBOs are " abstract " objects and are not shared . */
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2019-02-03 00:07:53 +01:00
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " [GL]: Initializing HW render (%ux%u). \n " , width , height ) ;
2019-02-03 00:07:53 +01:00
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & max_fbo_size ) ;
glGetIntegerv ( RARCH_GL_MAX_RENDERBUFFER_SIZE , & max_renderbuffer_size ) ;
RARCH_LOG ( " [GL]: Max texture size: %d px, renderbuffer size: %d px. \n " ,
max_fbo_size , max_renderbuffer_size ) ;
if ( ! gl - > has_fbo )
return false ;
RARCH_LOG ( " [GL]: Supports FBO (render-to-texture). \n " ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
gl2_gen_fb ( gl - > textures , gl - > hw_render_fbo ) ;
depth = hwr - > depth ;
stencil = hwr - > stencil ;
if ( depth )
{
gl2_gen_rb ( gl - > textures , chain - > hw_render_depth ) ;
chain - > hw_render_depth_init = true ;
}
for ( i = 0 ; i < gl - > textures ; i + + )
{
gl2_bind_fb ( gl - > hw_render_fbo [ i ] ) ;
gl2_fb_texture_2d ( RARCH_GL_FRAMEBUFFER ,
RARCH_GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , gl - > texture [ i ] , 0 ) ;
if ( depth )
{
gl2_bind_rb ( RARCH_GL_RENDERBUFFER , chain - > hw_render_depth [ i ] ) ;
gl2_rb_storage ( RARCH_GL_RENDERBUFFER ,
stencil ? RARCH_GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT16 ,
width , height ) ;
gl2_bind_rb ( RARCH_GL_RENDERBUFFER , 0 ) ;
if ( stencil )
{
2022-01-24 16:22:07 +01:00
# if defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES1) || (defined(__MACH__) && defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < 101200))
2019-02-03 00:07:53 +01:00
/* GLES2 is a bit weird, as always.
* There ' s no GL_DEPTH_STENCIL_ATTACHMENT like in desktop GL . */
gl2_fb_rb ( RARCH_GL_FRAMEBUFFER ,
RARCH_GL_DEPTH_ATTACHMENT ,
RARCH_GL_RENDERBUFFER ,
chain - > hw_render_depth [ i ] ) ;
gl2_fb_rb ( RARCH_GL_FRAMEBUFFER ,
RARCH_GL_STENCIL_ATTACHMENT ,
RARCH_GL_RENDERBUFFER ,
chain - > hw_render_depth [ i ] ) ;
# else
/* We use ARB FBO extensions, no need to check. */
gl2_fb_rb ( RARCH_GL_FRAMEBUFFER ,
GL_DEPTH_STENCIL_ATTACHMENT ,
RARCH_GL_RENDERBUFFER ,
chain - > hw_render_depth [ i ] ) ;
# endif
}
else
{
gl2_fb_rb ( RARCH_GL_FRAMEBUFFER ,
RARCH_GL_DEPTH_ATTACHMENT ,
RARCH_GL_RENDERBUFFER ,
chain - > hw_render_depth [ i ] ) ;
}
}
status = gl2_check_fb_status ( RARCH_GL_FRAMEBUFFER ) ;
if ( status ! = RARCH_GL_FRAMEBUFFER_COMPLETE )
{
RARCH_ERR ( " [GL]: Failed to create HW render FBO #%u, error: 0x%04x. \n " ,
i , status ) ;
return false ;
}
}
gl2_renderchain_bind_backbuffer ( ) ;
gl - > hw_render_fbo_init = true ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2019-02-03 00:07:53 +01:00
return true ;
}
static void gl2_renderchain_bind_prev_texture (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
const struct video_tex_info * tex_info )
{
memmove ( gl - > prev_info + 1 , gl - > prev_info ,
sizeof ( * tex_info ) * ( gl - > textures - 1 ) ) ;
memcpy ( & gl - > prev_info [ 0 ] , tex_info ,
sizeof ( * tex_info ) ) ;
/* Implement feedback by swapping out FBO/textures
* for FBO pass # N and feedbacks . */
if ( gl - > fbo_feedback_enable )
{
GLuint tmp_fbo = gl - > fbo_feedback ;
GLuint tmp_tex = gl - > fbo_feedback_texture ;
gl - > fbo_feedback = chain - > fbo [ gl - > fbo_feedback_pass ] ;
gl - > fbo_feedback_texture = chain - > fbo_texture [ gl - > fbo_feedback_pass ] ;
chain - > fbo [ gl - > fbo_feedback_pass ] = tmp_fbo ;
chain - > fbo_texture [ gl - > fbo_feedback_pass ] = tmp_tex ;
}
}
static bool gl2_renderchain_read_viewport (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
uint8_t * buffer , bool is_idle )
{
unsigned num_pixels = 0 ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2019-02-03 00:07:53 +01:00
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 ;
}
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2019-02-03 00:07:53 +01:00
return true ;
error :
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2019-02-03 00:07:53 +01:00
return false ;
}
2019-08-14 16:40:47 +02:00
# ifdef HAVE_OPENGLES
# define gl2_renderchain_restore_default_state(gl) \
glDisable ( GL_DEPTH_TEST ) ; \
glDisable ( GL_CULL_FACE ) ; \
glDisable ( GL_DITHER )
# else
# define gl2_renderchain_restore_default_state(gl) \
if ( ! gl - > core_context_in_use ) \
glEnable ( GL_TEXTURE_2D ) ; \
glDisable ( GL_DEPTH_TEST ) ; \
glDisable ( GL_CULL_FACE ) ; \
glDisable ( GL_DITHER )
2019-02-03 00:07:53 +01:00
# endif
static void gl2_renderchain_copy_frame (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
2020-03-09 15:40:14 +01:00
bool use_rgba ,
2019-02-03 00:07:53 +01:00
const void * frame ,
unsigned width , unsigned height , unsigned pitch )
{
# if defined(HAVE_PSGL)
{
unsigned h ;
size_t buffer_addr = gl - > tex_w * gl - > tex_h *
gl - > tex_index * gl - > base_size ;
size_t buffer_stride = gl - > tex_w * gl - > base_size ;
const uint8_t * frame_copy = frame ;
size_t frame_copy_size = width * gl - > base_size ;
uint8_t * buffer = ( uint8_t * ) glMapBuffer (
GL_TEXTURE_REFERENCE_BUFFER_SCE , GL_READ_WRITE ) + buffer_addr ;
for ( h = 0 ; h < height ; h + + , buffer + = buffer_stride , frame_copy + = pitch )
memcpy ( buffer , frame_copy , frame_copy_size ) ;
glUnmapBuffer ( GL_TEXTURE_REFERENCE_BUFFER_SCE ) ;
}
# elif defined(HAVE_OPENGLES)
# if defined(HAVE_EGL)
if ( chain - > egl_images )
{
bool new_egl = false ;
EGLImageKHR img = 0 ;
2020-07-27 08:25:11 +02:00
if ( gl - > ctx_driver - > image_buffer_write )
new_egl = gl - > ctx_driver - > image_buffer_write (
gl - > ctx_data ,
frame , width , height , pitch ,
( gl - > base_size = = 4 ) ,
gl - > tex_index ,
& img ) ;
2019-02-03 00:07:53 +01:00
if ( img = = EGL_NO_IMAGE_KHR )
{
RARCH_ERR ( " [GL]: Failed to create EGL image. \n " ) ;
return ;
}
if ( new_egl )
glEGLImageTargetTexture2DOES ( GL_TEXTURE_2D , ( GLeglImageOES ) img ) ;
}
else
# endif
{
glPixelStorei ( GL_UNPACK_ALIGNMENT ,
2021-03-11 02:03:37 +01:00
gl2_get_alignment ( width * gl - > base_size ) ) ;
2019-02-03 00:07:53 +01:00
/* Fallback for GLES devices without GL_BGRA_EXT. */
2020-03-09 15:40:14 +01:00
if ( gl - > base_size = = 4 & & use_rgba )
2019-02-03 00:07:53 +01:00
{
video_frame_convert_argb8888_to_abgr8888 (
& gl - > scaler ,
gl - > conv_buffer ,
frame , width , height , pitch ) ;
glTexSubImage2D ( GL_TEXTURE_2D ,
0 , 0 , 0 , width , height , gl - > texture_type ,
gl - > texture_fmt , gl - > conv_buffer ) ;
}
else if ( gl - > support_unpack_row_length )
{
glPixelStorei ( GL_UNPACK_ROW_LENGTH , pitch / gl - > base_size ) ;
glTexSubImage2D ( GL_TEXTURE_2D ,
0 , 0 , 0 , width , height , gl - > texture_type ,
gl - > texture_fmt , frame ) ;
glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 ) ;
}
else
{
/* No GL_UNPACK_ROW_LENGTH. */
const GLvoid * data_buf = frame ;
unsigned pitch_width = pitch / gl - > base_size ;
if ( width ! = pitch_width )
{
/* Slow path - conv_buffer is preallocated
* just in case we hit this path . */
unsigned h ;
const unsigned line_bytes = width * gl - > base_size ;
uint8_t * dst = ( uint8_t * ) gl - > conv_buffer ;
const uint8_t * src = ( const uint8_t * ) frame ;
for ( h = 0 ; h < height ; h + + , src + = pitch , dst + = line_bytes )
memcpy ( dst , src , line_bytes ) ;
data_buf = gl - > conv_buffer ;
}
glTexSubImage2D ( GL_TEXTURE_2D ,
0 , 0 , 0 , width , height , gl - > texture_type ,
gl - > texture_fmt , data_buf ) ;
}
}
# else
{
const GLvoid * data_buf = frame ;
2021-03-11 02:03:37 +01:00
glPixelStorei ( GL_UNPACK_ALIGNMENT , gl2_get_alignment ( pitch ) ) ;
2019-02-03 00:07:53 +01:00
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 ) ;
}
# endif
}
# if !defined(HAVE_OPENGLES2) && !defined(HAVE_PSGL)
2019-03-18 15:57:43 +01:00
# define gl2_renderchain_bind_pbo(idx) glBindBuffer(GL_PIXEL_PACK_BUFFER, (GLuint)idx)
# define gl2_renderchain_unbind_pbo() glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)
# define gl2_renderchain_init_pbo(size, data) glBufferData(GL_PIXEL_PACK_BUFFER, size, (const GLvoid*)data, GL_STREAM_READ)
# else
# define gl2_renderchain_bind_pbo(idx)
# define gl2_renderchain_unbind_pbo()
# define gl2_renderchain_init_pbo(size, data)
2019-02-03 00:07:53 +01:00
# endif
static void gl2_renderchain_readback (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
void * chain_data ,
unsigned alignment ,
unsigned fmt , unsigned type ,
void * src )
{
glPixelStorei ( GL_PACK_ALIGNMENT , alignment ) ;
# 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 ,
( GLenum ) fmt , ( GLenum ) type , ( GLvoid * ) src ) ;
}
static void gl2_renderchain_fence_iterate (
void * data ,
gl2_renderchain_data_t * chain ,
unsigned hard_sync_frames )
{
# ifndef HAVE_OPENGLES
# ifdef HAVE_GL_SYNC
chain - > fences [ chain - > fence_count + + ] =
glFenceSync ( GL_SYNC_GPU_COMMANDS_COMPLETE , 0 ) ;
while ( chain - > fence_count > hard_sync_frames )
{
glClientWaitSync ( chain - > fences [ 0 ] ,
GL_SYNC_FLUSH_COMMANDS_BIT , 1000000000 ) ;
glDeleteSync ( chain - > fences [ 0 ] ) ;
chain - > fence_count - - ;
memmove ( chain - > fences , chain - > fences + 1 ,
chain - > fence_count * sizeof ( void * ) ) ;
}
# endif
# endif
}
static void gl2_renderchain_fence_free ( void * data ,
gl2_renderchain_data_t * chain )
{
# ifndef HAVE_OPENGLES
# ifdef HAVE_GL_SYNC
unsigned i ;
for ( i = 0 ; i < chain - > fence_count ; i + + )
{
glClientWaitSync ( chain - > fences [ i ] ,
GL_SYNC_FLUSH_COMMANDS_BIT , 1000000000 ) ;
glDeleteSync ( chain - > fences [ i ] ) ;
}
chain - > fence_count = 0 ;
# endif
# endif
}
static void gl2_renderchain_init_texture_reference (
2021-09-26 17:42:12 +02:00
gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
unsigned i ,
unsigned internal_fmt , unsigned texture_fmt ,
unsigned texture_type )
{
# ifdef HAVE_PSGL
glTextureReferenceSCE ( GL_TEXTURE_2D , 1 ,
gl - > tex_w , gl - > tex_h , 0 ,
( GLenum ) internal_fmt ,
gl - > tex_w * gl - > base_size ,
gl - > tex_w * gl - > tex_h * i * gl - > base_size ) ;
# else
if ( chain - > egl_images )
return ;
2019-02-06 19:43:31 +01:00
gl2_load_texture_image ( GL_TEXTURE_2D ,
2019-02-03 00:07:53 +01:00
0 ,
( GLenum ) internal_fmt ,
gl - > tex_w , gl - > tex_h , 0 ,
( GLenum ) texture_type ,
( GLenum ) texture_fmt ,
gl - > empty_buf ? gl - > empty_buf : NULL ) ;
# endif
}
2021-09-26 17:42:12 +02:00
static void gl2_renderchain_resolve_extensions ( gl2_t * gl ,
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * chain ,
const char * context_ident ,
const video_info_t * video )
{
settings_t * settings = config_get_ptr ( ) ;
2020-02-18 14:51:40 +01:00
bool force_srgb_disable = settings - > bools . video_force_srgb_disable ;
2019-02-03 00:07:53 +01:00
if ( ! chain )
return ;
chain - > has_srgb_fbo = false ;
chain - > has_fp_fbo = gl_check_capability ( GL_CAPS_FP_FBO ) ;
/* GLES3 has unpack_subimage and sRGB in core. */
chain - > has_srgb_fbo_gles3 = gl_check_capability ( GL_CAPS_SRGB_FBO_ES3 ) ;
2020-02-18 14:51:40 +01:00
if ( ! force_srgb_disable )
2019-02-03 00:07:53 +01:00
chain - > has_srgb_fbo = gl_check_capability ( GL_CAPS_SRGB_FBO ) ;
/* Use regular textures if we use HW render. */
2019-08-29 11:26:28 +02:00
chain - > egl_images = ! gl - > hw_render_use
& & gl_check_capability ( GL_CAPS_EGLIMAGE )
& & gl - > ctx_driver - > image_buffer_init
& & gl - > ctx_driver - > image_buffer_init ( gl - > ctx_data , video ) ;
2015-12-08 09:44:19 +01:00
}
2019-02-02 21:47:31 +01:00
static void gl_load_texture_data (
2019-02-02 21:52:33 +01:00
GLuint id ,
2019-02-02 21:47:31 +01:00
enum gfx_wrap_type wrap_type ,
enum texture_filter_type filter_type ,
unsigned alignment ,
unsigned width , unsigned height ,
const void * frame , unsigned base_size )
{
GLint mag_filter , min_filter ;
bool want_mipmap = false ;
bool use_rgba = video_driver_supports_rgba ( ) ;
bool rgb32 = ( base_size = = ( sizeof ( uint32_t ) ) ) ;
2019-02-06 19:43:31 +01:00
GLenum wrap = gl2_wrap_type_to_enum ( wrap_type ) ;
2019-02-02 21:47:31 +01:00
bool have_mipmap = gl_check_capability ( GL_CAPS_MIPMAP ) ;
if ( ! have_mipmap )
{
/* Assume no mipmapping support. */
switch ( filter_type )
{
case TEXTURE_FILTER_MIPMAP_LINEAR :
filter_type = TEXTURE_FILTER_LINEAR ;
break ;
case TEXTURE_FILTER_MIPMAP_NEAREST :
filter_type = TEXTURE_FILTER_NEAREST ;
break ;
default :
break ;
}
}
switch ( filter_type )
{
case TEXTURE_FILTER_MIPMAP_LINEAR :
min_filter = GL_LINEAR_MIPMAP_NEAREST ;
mag_filter = GL_LINEAR ;
want_mipmap = true ;
break ;
case TEXTURE_FILTER_MIPMAP_NEAREST :
min_filter = GL_NEAREST_MIPMAP_NEAREST ;
mag_filter = GL_NEAREST ;
want_mipmap = true ;
break ;
case TEXTURE_FILTER_NEAREST :
min_filter = GL_NEAREST ;
mag_filter = GL_NEAREST ;
break ;
case TEXTURE_FILTER_LINEAR :
default :
min_filter = GL_LINEAR ;
mag_filter = GL_LINEAR ;
break ;
}
2021-09-26 17:42:12 +02:00
GL2_BIND_TEXTURE ( id , wrap , mag_filter , min_filter ) ;
2019-02-02 21:47:31 +01:00
glPixelStorei ( GL_UNPACK_ALIGNMENT , alignment ) ;
glTexImage2D ( GL_TEXTURE_2D ,
0 ,
( use_rgba | | ! rgb32 ) ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32 ,
width , height , 0 ,
( use_rgba | | ! rgb32 ) ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32 ,
( rgb32 ) ? RARCH_GL_FORMAT32 : GL_UNSIGNED_SHORT_4_4_4_4 , frame ) ;
if ( want_mipmap & & have_mipmap )
glGenerateMipmap ( GL_TEXTURE_2D ) ;
}
2019-02-06 19:43:31 +01:00
static bool gl2_add_lut (
2019-02-02 21:34:02 +01:00
const char * lut_path ,
bool lut_mipmap ,
unsigned lut_filter ,
enum gfx_wrap_type lut_wrap_type ,
2019-02-02 21:52:33 +01:00
unsigned i , GLuint * textures_lut )
2019-02-02 21:34:02 +01:00
{
struct texture_image img ;
enum texture_filter_type filter_type = TEXTURE_FILTER_LINEAR ;
img . width = 0 ;
img . height = 0 ;
img . pixels = NULL ;
img . supports_rgba = video_driver_supports_rgba ( ) ;
if ( ! image_texture_load ( & img , lut_path ) )
{
2021-12-04 15:21:12 +02:00
RARCH_ERR ( " [GL]: Failed to load texture image from: \" %s \" . \n " ,
2019-02-02 21:34:02 +01:00
lut_path ) ;
return false ;
}
RARCH_LOG ( " [GL]: Loaded texture image from: \" %s \" ... \n " ,
lut_path ) ;
if ( lut_filter = = RARCH_FILTER_NEAREST )
filter_type = TEXTURE_FILTER_NEAREST ;
if ( lut_mipmap )
{
if ( filter_type = = TEXTURE_FILTER_NEAREST )
filter_type = TEXTURE_FILTER_MIPMAP_NEAREST ;
else
filter_type = TEXTURE_FILTER_MIPMAP_LINEAR ;
}
gl_load_texture_data (
textures_lut [ i ] ,
lut_wrap_type ,
filter_type , 4 ,
img . width , img . height ,
img . pixels , sizeof ( uint32_t ) ) ;
image_texture_free ( & img ) ;
return true ;
}
2021-09-26 17:42:12 +02:00
bool gl2_load_luts (
2019-02-02 21:32:37 +01:00
const void * shader_data ,
GLuint * textures_lut )
{
unsigned i ;
2019-02-03 15:49:35 -08:00
const struct video_shader * shader =
2019-02-02 21:32:37 +01:00
( const struct video_shader * ) shader_data ;
unsigned num_luts = MIN ( shader - > luts , GFX_MAX_TEXTURES ) ;
if ( ! shader - > luts )
return true ;
glGenTextures ( num_luts , textures_lut ) ;
for ( i = 0 ; i < num_luts ; i + + )
{
2019-02-06 19:43:31 +01:00
if ( ! gl2_add_lut (
2019-02-02 21:32:37 +01:00
shader - > lut [ i ] . path ,
shader - > lut [ i ] . mipmap ,
shader - > lut [ i ] . filter ,
shader - > lut [ i ] . wrap ,
i , textures_lut ) )
return false ;
}
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
return true ;
}
2012-12-23 18:36:58 +01:00
# ifdef HAVE_OVERLAY
2021-09-26 17:42:12 +02:00
static void gl2_free_overlay ( gl2_t * gl )
2016-08-01 15:40:02 +02:00
{
glDeleteTextures ( gl - > overlays , gl - > overlay_tex ) ;
free ( gl - > overlay_tex ) ;
free ( gl - > overlay_vertex_coord ) ;
free ( gl - > overlay_tex_coord ) ;
free ( gl - > overlay_color_coord ) ;
gl - > overlay_tex = NULL ;
gl - > overlay_vertex_coord = NULL ;
gl - > overlay_tex_coord = NULL ;
gl - > overlay_color_coord = NULL ;
gl - > overlays = 0 ;
}
2019-02-06 19:43:31 +01:00
static void gl2_overlay_vertex_geom ( void * data ,
2013-10-15 16:06:59 +02:00
unsigned image ,
2016-08-01 15:40:02 +02:00
float x , float y ,
float w , float h )
{
GLfloat * vertex = NULL ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-08-01 15:40:02 +02:00
if ( ! gl )
return ;
if ( image > gl - > overlays )
{
2017-03-24 01:28:58 +01:00
RARCH_ERR ( " [GL]: Invalid overlay id: %u \n " , image ) ;
2016-08-01 15:40:02 +02:00
return ;
}
vertex = ( GLfloat * ) & gl - > overlay_vertex_coord [ image * 8 ] ;
/* Flipped, so we preserve top-down semantics. */
y = 1.0f - y ;
h = - h ;
vertex [ 0 ] = x ;
vertex [ 1 ] = y ;
vertex [ 2 ] = x + w ;
vertex [ 3 ] = y ;
vertex [ 4 ] = x ;
vertex [ 5 ] = y + h ;
vertex [ 6 ] = x + w ;
vertex [ 7 ] = y + h ;
}
2019-02-06 19:43:31 +01:00
static void gl2_overlay_tex_geom ( void * data ,
2013-10-15 16:06:59 +02:00
unsigned image ,
2016-08-01 15:40:02 +02:00
GLfloat x , GLfloat y ,
GLfloat w , GLfloat h )
{
GLfloat * tex = NULL ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-08-01 15:40:02 +02:00
if ( ! gl )
return ;
tex = ( GLfloat * ) & gl - > overlay_tex_coord [ image * 8 ] ;
tex [ 0 ] = x ;
tex [ 1 ] = y ;
tex [ 2 ] = x + w ;
tex [ 3 ] = y ;
tex [ 4 ] = x ;
tex [ 5 ] = y + h ;
tex [ 6 ] = x + w ;
tex [ 7 ] = y + h ;
}
2021-09-26 17:42:12 +02:00
static void gl2_render_overlay ( gl2_t * gl )
2016-08-01 15:40:02 +02:00
{
2017-09-09 00:20:39 +02:00
unsigned i ;
2020-03-07 00:58:06 +01:00
unsigned width = gl - > video_width ;
unsigned height = gl - > video_height ;
2016-08-01 15:40:02 +02:00
glEnable ( GL_BLEND ) ;
if ( gl - > overlay_full_screen )
glViewport ( 0 , 0 , width , height ) ;
/* Ensure that we reset the attrib array. */
2019-03-18 15:52:21 +01:00
gl - > shader - > use ( gl , gl - > shader_data ,
VIDEO_SHADER_STOCK_BLEND , true ) ;
2016-08-01 15:40:02 +02:00
gl - > coords . vertex = gl - > overlay_vertex_coord ;
gl - > coords . tex_coord = gl - > overlay_tex_coord ;
gl - > coords . color = gl - > overlay_color_coord ;
gl - > coords . vertices = 4 * gl - > overlays ;
2019-03-18 15:27:37 +01:00
gl - > shader - > set_coords ( gl - > shader_data , & gl - > coords ) ;
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp_no_rot ) ;
2016-08-01 15:40:02 +02:00
for ( i = 0 ; i < gl - > overlays ; i + + )
{
glBindTexture ( GL_TEXTURE_2D , gl - > overlay_tex [ i ] ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 4 * i , 4 ) ;
}
glDisable ( GL_BLEND ) ;
gl - > coords . vertex = gl - > vertex_ptr ;
gl - > coords . tex_coord = gl - > tex_info . coord ;
gl - > coords . color = gl - > white_color_ptr ;
gl - > coords . vertices = 4 ;
if ( gl - > overlay_full_screen )
glViewport ( gl - > vp . x , gl - > vp . y , gl - > vp . width , gl - > vp . height ) ;
}
2012-12-23 18:36:58 +01:00
# endif
2012-12-20 11:16:22 +01:00
2019-02-06 19:43:31 +01:00
static void gl2_set_viewport_wrapper ( void * data , unsigned viewport_width ,
2017-09-05 04:57:34 +02:00
unsigned viewport_height , bool force_full , bool allow_rotate )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-03-05 21:45:02 +01:00
gl2_set_viewport ( gl ,
2017-09-05 04:57:34 +02:00
viewport_width , viewport_height , force_full , allow_rotate ) ;
}
2013-03-28 20:23:30 -04:00
2014-10-01 20:06:40 +02:00
/* Shaders */
2019-06-04 21:52:58 +02:00
/**
* gl2_get_fallback_shader_type :
* @ type : shader type which should be used if possible
*
* Returns a supported fallback shader type in case the given one is not supported .
* For gl2 , shader support is completely defined by the context driver shader flags .
*
* gl2_get_fallback_shader_type ( RARCH_SHADER_NONE ) returns a default shader type .
* if gl2_get_fallback_shader_type ( type ) ! = type , type was not supported .
*
* Returns : A supported shader type .
* If RARCH_SHADER_NONE is returned , no shader backend is supported .
* */
static enum rarch_shader_type gl2_get_fallback_shader_type ( enum rarch_shader_type type )
2019-03-18 15:52:21 +01:00
{
2019-06-04 21:52:58 +02:00
# if defined(HAVE_GLSL) || defined(HAVE_CG)
unsigned i ;
if ( type ! = RARCH_SHADER_CG & & type ! = RARCH_SHADER_GLSL )
2019-03-18 15:52:21 +01:00
{
2019-06-04 21:52:58 +02:00
type = DEFAULT_SHADER_TYPE ;
2019-03-18 15:52:21 +01:00
2019-06-04 21:52:58 +02:00
if ( type ! = RARCH_SHADER_CG & & type ! = RARCH_SHADER_GLSL )
type = RARCH_SHADER_GLSL ;
}
2019-03-18 15:52:21 +01:00
2019-06-04 21:52:58 +02:00
for ( i = 0 ; i < 2 ; i + + )
{
switch ( type )
{
case RARCH_SHADER_CG :
# ifdef HAVE_CG
2019-06-17 14:10:55 +02:00
if ( video_shader_is_supported ( type ) )
return type ;
2019-06-04 21:52:58 +02:00
# endif
type = RARCH_SHADER_GLSL ;
2019-03-18 15:52:21 +01:00
break ;
2019-06-04 21:52:58 +02:00
case RARCH_SHADER_GLSL :
# ifdef HAVE_GLSL
2019-06-17 14:10:55 +02:00
if ( video_shader_is_supported ( type ) )
return type ;
2019-06-04 21:52:58 +02:00
# endif
type = RARCH_SHADER_CG ;
break ;
default :
return RARCH_SHADER_NONE ;
}
}
# endif
return RARCH_SHADER_NONE ;
}
static const shader_backend_t * gl_shader_driver_set_backend (
enum rarch_shader_type type )
{
enum rarch_shader_type fallback = gl2_get_fallback_shader_type ( type ) ;
if ( fallback ! = type )
2021-12-04 15:21:12 +02:00
RARCH_ERR ( " [Shader driver]: Shader backend %d not supported, falling back to %d. \n " , type , fallback ) ;
2019-06-04 21:52:58 +02:00
switch ( fallback )
{
# ifdef HAVE_CG
case RARCH_SHADER_CG :
RARCH_LOG ( " [Shader driver]: Using Cg shader backend. \n " ) ;
return & gl_cg_backend ;
2019-03-18 15:52:21 +01:00
# endif
# ifdef HAVE_GLSL
2019-06-04 21:52:58 +02:00
case RARCH_SHADER_GLSL :
2019-03-18 15:52:21 +01:00
RARCH_LOG ( " [Shader driver]: Using GLSL shader backend. \n " ) ;
return & gl_glsl_backend ;
# endif
default :
2019-06-04 21:52:58 +02:00
RARCH_LOG ( " [Shader driver]: No supported shader backend. \n " ) ;
return NULL ;
2019-03-18 15:52:21 +01:00
}
}
static bool gl_shader_driver_init ( video_shader_ctx_init_t * init )
{
void * tmp = NULL ;
settings_t * settings = config_get_ptr ( ) ;
if ( ! init - > shader | | ! init - > shader - > init )
{
init - > shader = gl_shader_driver_set_backend ( init - > shader_type ) ;
if ( ! init - > shader )
return false ;
}
tmp = init - > shader - > init ( init - > data , init - > path ) ;
if ( ! tmp )
return false ;
if ( string_is_equal ( settings - > arrays . menu_driver , " xmb " )
& & init - > shader - > init_menu_shaders )
{
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " Setting up menu pipeline shaders for XMB ... \n " ) ;
2019-03-18 15:52:21 +01:00
init - > shader - > init_menu_shaders ( tmp ) ;
}
2019-06-04 21:52:58 +02:00
init - > shader_data = tmp ;
2019-03-18 15:52:21 +01:00
return true ;
}
2012-09-15 15:37:08 +02:00
2021-09-26 17:42:12 +02:00
static bool gl2_shader_init ( gl2_t * gl , const gfx_ctx_driver_t * ctx_driver ,
2017-11-08 17:08:03 +01:00
struct retro_hw_render_callback * hwr
)
2011-01-05 17:22:12 +01:00
{
2016-02-14 18:41:45 +01:00
video_shader_ctx_init_t init_data ;
2019-06-04 21:52:58 +02:00
bool ret = false ;
const char * shader_path = retroarch_get_shader_preset ( ) ;
enum rarch_shader_type parse_type = video_shader_parse_type ( shader_path ) ;
enum rarch_shader_type type ;
type = gl2_get_fallback_shader_type ( parse_type ) ;
2018-08-17 07:49:25 -04:00
2019-06-17 18:26:41 +02:00
if ( type = = RARCH_SHADER_NONE )
2019-06-04 21:52:58 +02:00
{
RARCH_ERR ( " [GL]: Couldn't find any supported shader backend! Continuing without shaders. \n " ) ;
return true ;
}
2011-02-28 16:59:31 +01:00
2019-06-04 21:52:58 +02:00
if ( type ! = parse_type )
2013-04-07 01:38:11 +02:00
{
2019-06-04 21:52:58 +02:00
if ( ! string_is_empty ( shader_path ) )
2021-02-18 18:33:47 +02:00
RARCH_WARN ( " [GL]: Shader preset %s is using unsupported shader type %s, falling back to stock %s. \n " ,
2020-12-26 21:09:27 -05:00
shader_path , video_shader_type_to_str ( parse_type ) , video_shader_type_to_str ( type ) ) ;
2011-01-05 17:22:12 +01:00
2019-06-04 21:52:58 +02:00
shader_path = NULL ;
}
2011-01-05 17:22:12 +01:00
2019-06-19 22:34:05 +02:00
# ifdef HAVE_GLSL
2019-06-04 21:52:58 +02:00
if ( type = = RARCH_SHADER_GLSL )
gl_glsl_set_context_type ( gl - > core_context_in_use ,
2020-08-04 03:58:51 +02:00
hwr - > version_major , hwr - > version_minor ) ;
2019-06-19 22:34:05 +02:00
# endif
2016-04-16 05:14:39 +02:00
2017-11-08 05:59:08 +01:00
init_data . gl . core_context_enabled = gl - > core_context_in_use ;
2016-04-16 05:36:09 +02:00
init_data . shader_type = type ;
init_data . shader = NULL ;
2020-06-29 21:24:32 +02:00
init_data . shader_data = NULL ;
2016-04-16 05:36:09 +02:00
init_data . data = gl ;
init_data . path = shader_path ;
2016-02-14 18:41:45 +01:00
2019-03-18 15:52:21 +01:00
if ( gl_shader_driver_init ( & init_data ) )
2019-02-03 04:37:54 +01:00
{
gl - > shader = init_data . shader ;
gl - > shader_data = init_data . shader_data ;
2016-04-16 05:36:09 +02:00
return true ;
2019-02-03 04:37:54 +01:00
}
2016-02-14 18:41:45 +01:00
2016-04-16 05:36:09 +02:00
RARCH_ERR ( " [GL]: Failed to initialize shader, falling back to stock. \n " ) ;
2016-02-14 18:41:45 +01:00
2020-06-29 21:24:32 +02:00
init_data . shader = NULL ;
init_data . shader_data = NULL ;
init_data . path = NULL ;
2013-06-05 10:42:39 +02:00
2020-06-29 21:24:32 +02:00
ret = gl_shader_driver_init ( & init_data ) ;
2019-02-03 04:37:54 +01:00
2020-06-29 21:24:32 +02:00
gl - > shader = init_data . shader ;
gl - > shader_data = init_data . shader_data ;
2019-02-03 04:37:54 +01:00
return ret ;
2011-01-05 17:22:12 +01:00
}
2019-02-06 19:43:31 +01:00
static uintptr_t gl2_get_current_framebuffer ( void * data )
2016-08-01 18:08:18 +02:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2017-11-13 05:23:15 +01:00
if ( ! gl | | ! gl - > has_fbo )
2017-11-12 17:17:40 +01:00
return 0 ;
2016-08-01 18:08:18 +02:00
return gl - > hw_render_fbo [ ( gl - > tex_index + 1 ) % gl - > textures ] ;
}
2011-03-06 19:56:35 +01:00
2019-02-06 19:43:31 +01:00
static void gl2_set_rotation ( void * data , unsigned rotation )
2016-08-01 18:08:18 +02:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-08-01 18:08:18 +02:00
if ( ! gl )
return ;
gl - > rotation = 90 * rotation ;
2019-02-06 19:43:31 +01:00
gl2_set_projection ( gl , & default_ortho , true ) ;
2016-08-01 18:08:18 +02:00
}
2019-02-06 19:43:31 +01:00
static void gl2_set_video_mode ( void * data , unsigned width , unsigned height ,
2016-08-01 18:08:18 +02:00
bool fullscreen )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-07-27 11:08:34 +02:00
if ( gl - > ctx_driver - > set_video_mode )
gl - > ctx_driver - > set_video_mode ( gl - > ctx_data ,
width , height , fullscreen ) ;
2016-08-01 18:08:18 +02:00
}
2021-09-26 17:42:12 +02:00
static void gl2_update_input_size ( gl2_t * gl , unsigned width ,
2014-10-01 23:53:18 +02:00
unsigned height , unsigned pitch , bool clear )
2012-02-01 00:14:04 +01:00
{
2018-05-13 06:43:24 +02:00
float xamt , yamt ;
2014-10-01 16:59:43 +02:00
2016-09-17 20:57:17 -03:00
if ( ( width ! = gl - > last_width [ gl - > tex_index ] | |
2014-10-01 16:59:43 +02:00
height ! = gl - > last_height [ gl - > tex_index ] ) & & gl - > empty_buf )
2010-12-26 04:15:12 +01:00
{
2014-10-01 23:50:58 +02:00
/* Resolution change. Need to clear out texture. */
2016-03-24 03:32:00 +01:00
gl - > last_width [ gl - > tex_index ] = width ;
2011-07-03 15:39:35 +02:00
gl - > last_height [ gl - > tex_index ] = height ;
2012-05-27 22:39:29 +02:00
2013-03-27 16:15:15 +01:00
if ( clear )
{
2014-10-01 16:59:43 +02:00
glPixelStorei ( GL_UNPACK_ALIGNMENT ,
2021-03-11 02:03:37 +01:00
gl2_get_alignment ( width * sizeof ( uint32_t ) ) ) ;
2012-09-11 09:55:03 +02:00
# if defined(HAVE_PSGL)
2013-03-27 16:15:15 +01:00
glBufferSubData ( GL_TEXTURE_REFERENCE_BUFFER_SCE ,
gl - > tex_w * gl - > tex_h * gl - > tex_index * gl - > base_size ,
gl - > tex_w * gl - > tex_h * gl - > base_size ,
gl - > empty_buf ) ;
2012-05-27 22:39:29 +02:00
# else
2013-03-27 16:15:15 +01:00
glTexSubImage2D ( GL_TEXTURE_2D ,
0 , 0 , 0 , gl - > tex_w , gl - > tex_h , gl - > texture_type ,
gl - > texture_fmt , gl - > empty_buf ) ;
2012-05-27 22:39:29 +02:00
# endif
2013-03-27 16:15:15 +01:00
}
2010-12-26 04:15:12 +01:00
}
2018-05-13 06:43:24 +02:00
/* We might have used different texture coordinates
* last frame . Edge case if resolution changes very rapidly . */
2016-09-17 20:57:17 -03:00
else if ( ( width ! =
2015-02-13 02:21:54 +01:00
gl - > last_width [ ( gl - > tex_index + gl - > textures - 1 ) % gl - > textures ] ) | |
2016-09-17 20:57:17 -03:00
( height ! =
2018-05-13 06:43:24 +02:00
gl - > last_height [ ( gl - > tex_index + gl - > textures - 1 ) % gl - > textures ] ) ) { }
else
2015-02-13 02:21:54 +01:00
return ;
2018-05-13 06:43:24 +02:00
xamt = ( float ) width / gl - > tex_w ;
yamt = ( float ) height / gl - > tex_h ;
2020-09-01 19:54:41 +02:00
SET_TEXTURE_COORDS ( gl - > tex_info . coord , xamt , yamt ) ;
2012-02-01 00:14:04 +01:00
}
2011-06-01 12:19:48 +02:00
2021-09-26 17:42:12 +02:00
static void gl2_init_textures_data ( gl2_t * gl )
2012-11-18 14:21:47 +01:00
{
2017-09-09 00:20:39 +02:00
unsigned i ;
2016-03-24 03:32:00 +01:00
2013-10-22 15:08:17 +02:00
for ( i = 0 ; i < gl - > textures ; i + + )
2012-11-18 14:21:47 +01:00
{
gl - > last_width [ i ] = gl - > tex_w ;
gl - > last_height [ i ] = gl - > tex_h ;
}
2013-10-22 15:08:17 +02:00
for ( i = 0 ; i < gl - > textures ; i + + )
2012-11-18 14:21:47 +01:00
{
2012-12-10 13:02:59 +01:00
gl - > prev_info [ i ] . tex = gl - > texture [ 0 ] ;
2012-11-18 14:21:47 +01:00
gl - > prev_info [ i ] . input_size [ 0 ] = gl - > tex_w ;
gl - > prev_info [ i ] . tex_size [ 0 ] = gl - > tex_w ;
gl - > prev_info [ i ] . input_size [ 1 ] = gl - > tex_h ;
gl - > prev_info [ i ] . tex_size [ 1 ] = gl - > tex_h ;
2016-09-17 20:57:17 -03:00
memcpy ( gl - > prev_info [ i ] . coord , tex_coords , sizeof ( tex_coords ) ) ;
2012-11-18 14:21:47 +01:00
}
}
2021-09-26 17:42:12 +02:00
static void gl2_init_textures ( gl2_t * gl )
2012-05-26 16:01:59 +02:00
{
2017-09-09 00:20:39 +02:00
unsigned i ;
2017-12-04 13:03:14 +01:00
GLenum internal_fmt = gl - > internal_fmt ;
GLenum texture_type = gl - > texture_type ;
GLenum texture_fmt = gl - > texture_fmt ;
2013-04-06 18:40:50 +02:00
# ifdef HAVE_PSGL
2012-11-10 23:56:04 +01:00
if ( ! gl - > pbo )
glGenBuffers ( 1 , & gl - > pbo ) ;
glBindBuffer ( GL_TEXTURE_REFERENCE_BUFFER_SCE , gl - > pbo ) ;
glBufferData ( GL_TEXTURE_REFERENCE_BUFFER_SCE ,
2016-09-17 20:57:17 -03:00
gl - > tex_w * gl - > tex_h * gl - > base_size * gl - > textures ,
2016-02-14 16:59:21 +01:00
NULL , GL_STREAM_DRAW ) ;
2013-04-06 18:40:50 +02:00
# endif
2012-11-10 23:56:04 +01:00
2016-12-30 13:56:54 -07:00
# if defined(HAVE_OPENGLES) && !defined(HAVE_PSGL)
2014-10-01 23:50:58 +02:00
/* GLES is picky about which format we use here.
* Without extensions , we can * only * render to 16 - bit FBOs . */
2013-05-18 21:53:26 +02:00
if ( gl - > hw_render_use & & gl - > base_size = = sizeof ( uint32_t ) )
{
2016-08-01 16:01:21 +02:00
if ( gl_check_capability ( GL_CAPS_ARGB8 ) )
2013-05-18 21:53:26 +02:00
{
2016-12-14 09:54:55 -08:00
internal_fmt = GL_RGBA ;
2013-05-18 21:53:26 +02:00
texture_type = GL_RGBA ;
texture_fmt = GL_UNSIGNED_BYTE ;
}
else
{
RARCH_WARN ( " [GL]: 32-bit FBO not supported. Falling back to 16-bit. \n " ) ;
internal_fmt = GL_RGB ;
texture_type = GL_RGB ;
texture_fmt = GL_UNSIGNED_SHORT_5_6_5 ;
}
}
# endif
2013-07-06 22:10:09 +02:00
glGenTextures ( gl - > textures , gl - > texture ) ;
2012-05-26 16:01:59 +02:00
2013-10-22 15:08:17 +02:00
for ( i = 0 ; i < gl - > textures ; i + + )
2017-11-08 17:10:41 +01:00
{
2021-09-26 17:42:12 +02:00
GL2_BIND_TEXTURE ( gl - > texture [ i ] , gl - > wrap_mode , gl - > tex_mag_filter ,
2017-11-10 03:55:10 +01:00
gl - > tex_min_filter ) ;
2017-11-08 17:10:41 +01:00
2019-02-03 00:07:53 +01:00
gl2_renderchain_init_texture_reference (
2019-02-07 23:16:25 +01:00
gl , ( gl2_renderchain_data_t * ) gl - > renderchain_data ,
i , internal_fmt ,
2019-02-03 00:07:53 +01:00
texture_fmt , texture_type ) ;
2017-11-08 17:10:41 +01:00
}
2012-05-26 16:01:59 +02:00
glBindTexture ( GL_TEXTURE_2D , gl - > texture [ gl - > tex_index ] ) ;
}
2013-04-06 18:40:50 +02:00
2021-09-26 17:42:12 +02:00
static INLINE void gl2_set_shader_viewports ( gl2_t * gl )
2012-10-01 04:04:50 +02:00
{
2019-08-13 12:14:33 +02:00
unsigned i ;
unsigned width = gl - > video_width ;
unsigned height = gl - > video_height ;
2015-05-20 00:45:42 +02:00
2018-05-13 14:34:41 +02:00
for ( i = 0 ; i < 2 ; i + + )
{
2019-03-18 15:52:21 +01:00
gl - > shader - > use ( gl , gl - > shader_data , i , true ) ;
2020-03-05 21:45:02 +01:00
gl2_set_viewport ( gl , width , height , false , true ) ;
2018-05-13 14:34:41 +02:00
}
2012-10-01 04:04:50 +02:00
}
2019-02-06 19:43:31 +01:00
static void gl2_set_texture_frame ( void * data ,
2016-08-01 18:10:34 +02:00
const void * frame , bool rgb32 , unsigned width , unsigned height ,
float alpha )
{
settings_t * settings = config_get_ptr ( ) ;
2020-02-18 14:51:40 +01:00
enum texture_filter_type
2020-02-19 19:23:10 +01:00
menu_filter = settings - > bools . menu_linear_filter
? TEXTURE_FILTER_LINEAR
: TEXTURE_FILTER_NEAREST ;
2016-08-01 18:10:34 +02:00
unsigned base_size = rgb32 ? sizeof ( uint32_t ) : sizeof ( uint16_t ) ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-08-01 18:10:34 +02:00
if ( ! gl )
return ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2016-08-01 18:10:34 +02:00
if ( ! gl - > menu_texture )
glGenTextures ( 1 , & gl - > menu_texture ) ;
gl_load_texture_data ( gl - > menu_texture ,
RARCH_WRAP_EDGE , menu_filter ,
2021-03-11 02:03:37 +01:00
gl2_get_alignment ( width * base_size ) ,
2016-08-01 18:10:34 +02:00
width , height , frame ,
base_size ) ;
gl - > menu_texture_alpha = alpha ;
glBindTexture ( GL_TEXTURE_2D , gl - > texture [ gl - > tex_index ] ) ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2016-08-01 18:10:34 +02:00
}
2019-02-06 19:43:31 +01:00
static void gl2_set_texture_enable ( void * data , bool state , bool full_screen )
2016-08-01 18:10:34 +02:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-08-01 18:10:34 +02:00
if ( ! gl )
return ;
gl - > menu_texture_enable = state ;
gl - > menu_texture_full_screen = full_screen ;
}
2021-09-26 17:42:12 +02:00
static void gl2_render_osd_background ( gl2_t * gl , const char * msg )
2017-10-04 00:04:17 -04:00
{
video_coords_t coords ;
struct uniform_info uniform_param ;
2017-10-10 14:00:49 -04:00
float colors [ 4 ] ;
2017-12-11 23:55:31 -08:00
const unsigned
2017-11-08 18:31:17 +01:00
vertices_total = 6 ;
float * dummy = ( float * ) calloc ( 4 * vertices_total , sizeof ( float ) ) ;
float * verts = ( float * ) malloc ( 2 * vertices_total * sizeof ( float ) ) ;
settings_t * settings = config_get_ptr ( ) ;
2020-02-18 14:51:40 +01:00
float video_font_size = settings - > floats . video_font_size ;
2017-12-11 23:55:31 -08:00
int msg_width =
2018-04-09 15:56:45 +02:00
font_driver_get_message_width ( NULL , msg , ( unsigned ) strlen ( msg ) , 1.0f ) ;
2017-10-10 14:00:49 -04:00
/* shader driver expects vertex coords as 0..1 */
2020-03-07 00:58:06 +01:00
float x = settings - > floats . video_msg_pos_x ;
float y = settings - > floats . video_msg_pos_y ;
float width = msg_width / ( float ) gl - > video_width ;
float height = video_font_size / ( float ) gl - > video_height ;
2017-11-13 09:19:33 +01:00
float x2 = 0.005f ; /* extend background around text */
float y2 = 0.005f ;
2017-10-04 00:04:17 -04:00
2017-11-08 18:31:17 +01:00
x - = x2 ;
y - = y2 ;
width + = x2 ;
height + = y2 ;
2017-10-09 23:30:11 -04:00
2017-11-08 18:31:17 +01:00
colors [ 0 ] = settings - > uints . video_msg_bgcolor_red / 255.0f ;
colors [ 1 ] = settings - > uints . video_msg_bgcolor_green / 255.0f ;
colors [ 2 ] = settings - > uints . video_msg_bgcolor_blue / 255.0f ;
colors [ 3 ] = settings - > floats . video_msg_bgcolor_opacity ;
2017-10-09 23:30:11 -04:00
2017-10-10 15:28:29 -04:00
/* triangle 1 */
2017-11-08 18:31:17 +01:00
verts [ 0 ] = x ;
verts [ 1 ] = y ; /* bottom-left */
2017-10-04 00:04:17 -04:00
2017-11-08 18:31:17 +01:00
verts [ 2 ] = x ;
verts [ 3 ] = y + height ; /* top-left */
2017-10-04 00:04:17 -04:00
2017-11-08 18:31:17 +01:00
verts [ 4 ] = x + width ;
verts [ 5 ] = y + height ; /* top-right */
2017-10-04 00:04:17 -04:00
2017-10-10 15:28:29 -04:00
/* triangle 2 */
2017-11-08 18:31:17 +01:00
verts [ 6 ] = x ;
verts [ 7 ] = y ; /* bottom-left */
2017-10-04 00:04:17 -04:00
2017-11-08 18:31:17 +01:00
verts [ 8 ] = x + width ;
verts [ 9 ] = y + height ; /* top-right */
2017-10-04 00:04:17 -04:00
2017-11-08 18:31:17 +01:00
verts [ 10 ] = x + width ;
verts [ 11 ] = y ; /* bottom-right */
2017-10-04 00:04:17 -04:00
2017-11-08 18:31:17 +01:00
coords . color = dummy ;
coords . vertex = verts ;
coords . tex_coord = dummy ;
coords . lut_tex_coord = dummy ;
coords . vertices = vertices_total ;
2017-10-04 00:04:17 -04:00
2020-09-15 11:11:32 +02:00
gl2_set_viewport ( gl ,
gl - > video_width ,
2020-03-07 00:58:06 +01:00
gl - > video_height , true , false ) ;
2017-10-04 00:04:17 -04:00
2019-03-18 15:52:21 +01:00
gl - > shader - > use ( gl , gl - > shader_data ,
VIDEO_SHADER_STOCK_BLEND , true ) ;
2017-11-13 09:19:33 +01:00
2019-03-18 15:27:37 +01:00
gl - > shader - > set_coords ( gl - > shader_data , & coords ) ;
2017-10-04 00:04:17 -04:00
2017-10-10 14:00:49 -04:00
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glBlendEquation ( GL_FUNC_ADD ) ;
2017-10-09 23:30:11 -04:00
2019-03-18 15:27:37 +01:00
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp_no_rot ) ;
2017-10-04 00:04:17 -04:00
uniform_param . type = UNIFORM_4F ;
uniform_param . enabled = true ;
uniform_param . location = 0 ;
uniform_param . count = 0 ;
uniform_param . lookup . type = SHADER_PROGRAM_FRAGMENT ;
uniform_param . lookup . ident = " bgcolor " ;
2017-11-13 09:19:33 +01:00
uniform_param . lookup . idx = VIDEO_SHADER_STOCK_BLEND ;
2017-10-04 00:04:17 -04:00
uniform_param . lookup . add_prefix = true ;
uniform_param . lookup . enable = true ;
uniform_param . result . f . v0 = colors [ 0 ] ;
uniform_param . result . f . v1 = colors [ 1 ] ;
uniform_param . result . f . v2 = colors [ 2 ] ;
uniform_param . result . f . v3 = colors [ 3 ] ;
2019-02-06 19:49:45 +01:00
gl - > shader - > set_uniform_parameter ( gl - > shader_data ,
& uniform_param , NULL ) ;
2017-10-04 00:04:17 -04:00
glDrawArrays ( GL_TRIANGLES , 0 , coords . vertices ) ;
2017-11-13 09:19:33 +01:00
2017-10-10 15:28:29 -04:00
/* reset uniform back to zero so it is not used for anything else */
2017-10-10 14:00:49 -04:00
uniform_param . result . f . v0 = 0.0f ;
uniform_param . result . f . v1 = 0.0f ;
uniform_param . result . f . v2 = 0.0f ;
uniform_param . result . f . v3 = 0.0f ;
2017-10-09 23:30:11 -04:00
2019-02-06 19:49:45 +01:00
gl - > shader - > set_uniform_parameter ( gl - > shader_data ,
& uniform_param , NULL ) ;
2017-10-09 23:30:11 -04:00
2017-10-04 00:04:17 -04:00
free ( dummy ) ;
free ( verts ) ;
2020-09-15 11:11:32 +02:00
gl2_set_viewport ( gl ,
gl - > video_width ,
2020-03-07 00:58:06 +01:00
gl - > video_height , false , true ) ;
2017-10-04 00:04:17 -04:00
}
2019-02-06 19:43:31 +01:00
static void gl2_show_mouse ( void * data , bool state )
2016-08-01 18:10:34 +02:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2019-08-28 21:36:58 +02:00
if ( gl & & gl - > ctx_driver - > show_mouse )
gl - > ctx_driver - > show_mouse ( gl - > ctx_data , state ) ;
2016-08-01 18:10:34 +02:00
}
2019-02-06 19:43:31 +01:00
static struct video_shader * gl2_get_current_shader ( void * data )
2016-08-01 18:10:34 +02:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-08-01 18:10:34 +02:00
2019-02-03 06:28:27 +01:00
if ( ! gl )
return NULL ;
2016-08-01 18:10:34 +02:00
2019-02-03 06:28:27 +01:00
return gl - > shader - > get_current_shader ( gl - > shader_data ) ;
2016-08-01 18:10:34 +02:00
}
2018-08-16 09:59:51 +02:00
# if defined(HAVE_MENU)
2021-09-26 17:42:12 +02:00
static INLINE void gl2_draw_texture ( gl2_t * gl )
2013-02-27 20:20:29 -05:00
{
2015-06-30 19:07:53 +02:00
GLfloat color [ 16 ] ;
2020-03-07 00:58:06 +01:00
unsigned width = gl - > video_width ;
unsigned height = gl - > video_height ;
2015-06-30 19:07:53 +02:00
2017-11-08 18:22:05 +01:00
color [ 0 ] = 1.0f ;
color [ 1 ] = 1.0f ;
color [ 2 ] = 1.0f ;
color [ 3 ] = gl - > menu_texture_alpha ;
color [ 4 ] = 1.0f ;
color [ 5 ] = 1.0f ;
color [ 6 ] = 1.0f ;
color [ 7 ] = gl - > menu_texture_alpha ;
color [ 8 ] = 1.0f ;
color [ 9 ] = 1.0f ;
color [ 10 ] = 1.0f ;
color [ 11 ] = gl - > menu_texture_alpha ;
color [ 12 ] = 1.0f ;
color [ 13 ] = 1.0f ;
color [ 14 ] = 1.0f ;
color [ 15 ] = gl - > menu_texture_alpha ;
2015-05-20 00:45:42 +02:00
2017-11-08 18:31:17 +01:00
gl - > coords . vertex = vertexes_flipped ;
gl - > coords . tex_coord = tex_coords ;
gl - > coords . color = color ;
2017-11-16 14:01:20 +01:00
2014-06-10 02:15:29 +02:00
glBindTexture ( GL_TEXTURE_2D , gl - > menu_texture ) ;
2013-02-27 20:20:29 -05:00
2019-03-18 15:52:21 +01:00
gl - > shader - > use ( gl ,
gl - > shader_data , VIDEO_SHADER_STOCK_BLEND , true ) ;
2016-02-14 18:59:42 +01:00
2017-11-16 14:01:20 +01:00
gl - > coords . vertices = 4 ;
2016-02-14 18:59:42 +01:00
2019-03-18 15:27:37 +01:00
gl - > shader - > set_coords ( gl - > shader_data , & gl - > coords ) ;
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp_no_rot ) ;
2013-02-27 20:20:29 -05:00
glEnable ( GL_BLEND ) ;
2013-04-13 16:48:03 +02:00
2014-06-10 02:15:29 +02:00
if ( gl - > menu_texture_full_screen )
2013-04-13 16:48:03 +02:00
{
2015-05-20 00:45:42 +02:00
glViewport ( 0 , 0 , width , height ) ;
2013-04-13 16:48:03 +02:00
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
glViewport ( gl - > vp . x , gl - > vp . y , gl - > vp . width , gl - > vp . height ) ;
}
else
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
2013-02-27 20:20:29 -05:00
glDisable ( GL_BLEND ) ;
2017-11-16 14:01:20 +01:00
gl - > coords . vertex = gl - > vertex_ptr ;
gl - > coords . tex_coord = gl - > tex_info . coord ;
gl - > coords . color = gl - > white_color_ptr ;
2013-02-27 20:20:29 -05:00
}
# endif
2021-09-26 17:42:12 +02:00
static void gl2_pbo_async_readback ( gl2_t * gl )
2017-12-31 17:53:11 +01:00
{
# ifdef HAVE_OPENGLES
GLenum fmt = GL_RGBA ;
GLenum type = GL_UNSIGNED_BYTE ;
# else
GLenum fmt = GL_BGRA ;
GLenum type = GL_UNSIGNED_INT_8_8_8_8_REV ;
# endif
2019-02-03 00:07:53 +01:00
gl2_renderchain_bind_pbo (
2017-12-31 17:53:11 +01:00
gl - > pbo_readback [ gl - > pbo_readback_index + + ] ) ;
gl - > pbo_readback_index & = 3 ;
/* 4 frames back, we can readback. */
gl - > pbo_readback_valid [ gl - > pbo_readback_index ] = true ;
2019-02-03 00:07:53 +01:00
gl2_renderchain_readback ( gl , gl - > renderchain_data ,
2021-03-11 02:03:37 +01:00
gl2_get_alignment ( gl - > vp . width * sizeof ( uint32_t ) ) ,
2019-02-03 00:07:53 +01:00
fmt , type , NULL ) ;
gl2_renderchain_unbind_pbo ( ) ;
2017-12-31 17:53:11 +01:00
}
2019-04-03 05:04:17 +01:00
# ifdef HAVE_VIDEO_LAYOUT
static float video_layout_layer_tex_coord [ ] = {
0.0f , 1.0f ,
1.0f , 1.0f ,
0.0f , 0.0f ,
1.0f , 0.0f ,
} ;
2021-09-26 17:42:12 +02:00
static void gl2_video_layout_fbo_init ( gl2_t * gl , unsigned width , unsigned height )
2019-04-03 05:04:17 +01:00
{
glGenTextures ( 1 , & gl - > video_layout_fbo_texture ) ;
glBindTexture ( GL_TEXTURE_2D , gl - > video_layout_fbo_texture ) ;
gl2_load_texture_image ( GL_TEXTURE_2D , 0 , RARCH_GL_INTERNAL_FORMAT32 ,
width , height , 0 , GL_RGBA , GL_FLOAT , NULL ) ;
gl2_gen_fb ( 1 , & gl - > video_layout_fbo ) ;
gl2_bind_fb ( gl - > video_layout_fbo ) ;
gl2_fb_texture_2d ( RARCH_GL_FRAMEBUFFER , RARCH_GL_COLOR_ATTACHMENT0 ,
GL_TEXTURE_2D , gl - > video_layout_fbo_texture , 0 ) ;
2019-05-13 01:07:02 +02:00
if ( gl2_check_fb_status ( RARCH_GL_FRAMEBUFFER ) ! =
RARCH_GL_FRAMEBUFFER_COMPLETE )
2021-12-04 15:21:12 +02:00
RARCH_ERR ( " [GL]: Unable to create FBO for video_layout. \n " ) ;
2019-04-03 05:04:17 +01:00
gl2_bind_fb ( 0 ) ;
}
2021-09-26 17:42:12 +02:00
static void gl2_video_layout_fbo_free ( gl2_t * gl )
2019-04-03 05:04:17 +01:00
{
if ( gl - > video_layout_fbo )
{
gl2_delete_fb ( 1 , & gl - > video_layout_fbo ) ;
gl - > video_layout_fbo = 0 ;
}
if ( gl - > video_layout_fbo_texture )
{
glDeleteTextures ( 1 , & gl - > video_layout_fbo_texture ) ;
gl - > video_layout_fbo_texture = 0 ;
}
}
2021-09-26 17:42:12 +02:00
static void gl2_video_layout_viewport ( gl2_t * gl )
2019-04-03 05:04:17 +01:00
{
if ( ! video_layout_valid ( ) )
return ;
if ( gl - > video_layout_resize )
{
if ( gl - > video_layout_fbo )
gl2_video_layout_fbo_free ( gl ) ;
2020-03-07 00:58:06 +01:00
gl2_video_layout_fbo_init ( gl , gl - > video_width , gl - > video_height ) ;
2019-04-03 05:04:17 +01:00
video_layout_view_change ( ) ;
gl - > video_layout_resize = false ;
}
if ( video_layout_view_on_change ( ) )
{
video_layout_bounds_t b ;
b . x = 0.0f ;
b . y = 0.0f ;
2020-03-07 00:58:06 +01:00
b . w = ( float ) gl - > video_width ;
b . h = ( float ) gl - > video_height ;
2019-04-03 05:04:17 +01:00
video_layout_view_fit_bounds ( b ) ;
}
if ( video_layout_screen_count ( ) )
{
const video_layout_bounds_t * bounds ;
bounds = video_layout_screen ( 0 ) ;
glViewport (
2020-03-07 00:58:06 +01:00
bounds - > x , gl - > video_height - bounds - > y - bounds - > h ,
2019-04-03 05:04:17 +01:00
bounds - > w , bounds - > h
) ;
}
}
2021-09-26 17:42:12 +02:00
static void gl2_video_layout_render ( gl2_t * gl )
2019-04-03 05:04:17 +01:00
{
int i ;
if ( ! video_layout_valid ( ) )
return ;
2020-03-07 00:58:06 +01:00
glViewport ( 0 , 0 , gl - > video_width , gl - > video_height ) ;
2019-04-03 05:04:17 +01:00
glEnable ( GL_BLEND ) ;
for ( i = 0 ; i < video_layout_layer_count ( ) ; + + i )
2020-03-10 19:10:02 +01:00
video_layout_layer_render ( i ) ;
2019-04-03 05:04:17 +01:00
glDisable ( GL_BLEND ) ;
}
2021-09-26 17:42:12 +02:00
static void gl2_video_layout_init ( gl2_t * gl )
2019-04-03 05:04:17 +01:00
{
uint32_t px ;
gl - > video_layout_resize = true ;
/* white 1px texture for drawing solid colors */
px = 0xFFFFFFFF ;
glGenTextures ( 1 , & gl - > video_layout_white_texture ) ;
gl_load_texture_data ( gl - > video_layout_white_texture ,
RARCH_WRAP_EDGE , TEXTURE_FILTER_NEAREST ,
sizeof ( uint32_t ) , 1 , 1 , & px , sizeof ( uint32_t ) ) ;
}
2021-09-26 17:42:12 +02:00
static void gl2_video_layout_free ( gl2_t * gl )
2019-04-03 05:04:17 +01:00
{
gl2_video_layout_fbo_free ( gl ) ;
if ( gl - > video_layout_white_texture )
{
glDeleteTextures ( 1 , & gl - > video_layout_white_texture ) ;
gl - > video_layout_white_texture = 0 ;
}
}
static void * gl2_video_layout_take_image ( void * video_driver_data , struct texture_image image )
{
2021-03-11 02:03:37 +01:00
GLuint tex = 0 ;
unsigned alignment = gl2_get_alignment ( image . width * sizeof ( uint32_t ) ) ;
2019-04-03 05:04:17 +01:00
glGenTextures ( 1 , & tex ) ;
gl_load_texture_data ( tex ,
RARCH_WRAP_EDGE , TEXTURE_FILTER_MIPMAP_LINEAR ,
alignment , image . width , image . height , image . pixels , sizeof ( uint32_t ) ) ;
free ( image . pixels ) ;
return ( void * ) ( uintptr_t ) tex ;
}
static void gl2_video_layout_free_image ( void * video_driver_data , void * image )
{
GLuint tex ;
tex = ( GLuint ) ( uintptr_t ) image ;
glDeleteTextures ( 1 , & tex ) ;
}
static void gl2_video_layout_layer_begin ( const video_layout_render_info_t * info )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl ;
gl = ( gl2_t * ) info - > video_driver_data ;
2019-04-03 05:04:17 +01:00
gl2_bind_fb ( gl - > video_layout_fbo ) ;
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
gl - > shader - > use ( gl , gl - > shader_data ,
VIDEO_SHADER_STOCK_BLEND , true ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
}
2020-06-26 20:00:19 +02:00
static void gl2_video_layout_image (
const video_layout_render_info_t * info ,
void * image_handle , void * alpha_handle )
2019-04-03 05:04:17 +01:00
{
/* TODO alpha_handle */
2020-03-07 00:58:06 +01:00
int i ;
2019-04-03 05:04:17 +01:00
float coord [ 8 ] ;
float color [ 16 ] ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) info - > video_driver_data ;
2020-03-07 00:58:06 +01:00
video_layout_bounds_t b = info - > bounds ;
2019-04-03 05:04:17 +01:00
2020-03-07 00:58:06 +01:00
b . x / = gl - > video_width ;
b . y / = gl - > video_height ;
b . w / = gl - > video_width ;
b . h / = gl - > video_height ;
2019-04-03 05:04:17 +01:00
coord [ 0 ] = b . x ;
coord [ 1 ] = 1.f - b . y ;
coord [ 2 ] = b . x + b . w ;
coord [ 3 ] = 1.f - b . y ;
coord [ 4 ] = b . x ;
coord [ 5 ] = 1.f - ( b . y + b . h ) ;
coord [ 6 ] = b . x + b . w ;
coord [ 7 ] = 1.f - ( b . y + b . h ) ;
i = 0 ;
2020-06-26 20:00:19 +02:00
while ( i < 16 )
2019-04-03 05:04:17 +01:00
{
color [ i + + ] = info - > color . r ;
color [ i + + ] = info - > color . g ;
color [ i + + ] = info - > color . b ;
color [ i + + ] = info - > color . a ;
}
2020-06-26 20:00:19 +02:00
gl - > coords . vertex = coord ;
2019-04-03 05:04:17 +01:00
gl - > coords . tex_coord = tex_coords ;
2020-06-26 20:00:19 +02:00
gl - > coords . color = color ;
gl - > coords . vertices = 4 ;
2019-04-03 05:04:17 +01:00
gl - > shader - > set_coords ( gl - > shader_data , & gl - > coords ) ;
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp_no_rot ) ;
glBindTexture ( GL_TEXTURE_2D , ( GLuint ) ( uintptr_t ) image_handle ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
static void gl2_video_layout_text ( const video_layout_render_info_t * info , const char * str )
{
/* TODO */
}
static void gl2_video_layout_counter ( const video_layout_render_info_t * info , int value )
{
/* TODO */
}
static void gl2_video_layout_rect ( const video_layout_render_info_t * info )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl ;
gl = ( gl2_t * ) info - > video_driver_data ;
2019-04-03 05:04:17 +01:00
gl2_video_layout_image ( info , ( void * ) ( uintptr_t ) gl - > video_layout_white_texture , NULL ) ;
}
static void gl2_video_layout_screen ( const video_layout_render_info_t * info , int screen_index )
{
gl2_video_layout_rect ( info ) ;
}
static void gl2_video_layout_ellipse ( const video_layout_render_info_t * info )
{
/* TODO */
}
static void gl2_video_layout_led_dot ( const video_layout_render_info_t * info , int dot_count , int dot_mask )
{
/* TODO */
}
static void gl2_video_layout_led_seg ( const video_layout_render_info_t * info , video_layout_led_t seg_layout , int seg_mask )
{
/* TODO */
}
static void gl2_video_layout_layer_end ( const video_layout_render_info_t * info , video_layout_blend_t blend_type )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl ;
gl = ( gl2_t * ) info - > video_driver_data ;
2019-04-03 05:04:17 +01:00
switch ( blend_type )
{
case VIDEO_LAYOUT_BLEND_ALPHA :
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
case VIDEO_LAYOUT_BLEND_ADD :
glBlendFunc ( GL_ONE , GL_ONE ) ;
break ;
case VIDEO_LAYOUT_BLEND_MOD :
glBlendFunc ( GL_DST_COLOR , GL_ZERO ) ;
break ;
}
gl2_bind_fb ( 0 ) ;
gl - > coords . vertex = gl - > vertex_ptr ;
gl - > coords . tex_coord = video_layout_layer_tex_coord ;
gl - > coords . color = gl - > white_color_ptr ;
gl - > coords . vertices = 4 ;
gl - > shader - > set_coords ( gl - > shader_data , & gl - > coords ) ;
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp_no_rot ) ;
glBindTexture ( GL_TEXTURE_2D , gl - > video_layout_fbo_texture ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
gl - > coords . tex_coord = gl - > tex_info . coord ;
}
static video_layout_render_interface_t gl2_video_layout_render_interface =
{
gl2_video_layout_take_image ,
gl2_video_layout_free_image ,
gl2_video_layout_layer_begin ,
gl2_video_layout_screen ,
gl2_video_layout_image ,
gl2_video_layout_text ,
gl2_video_layout_counter ,
gl2_video_layout_rect ,
gl2_video_layout_ellipse ,
gl2_video_layout_led_dot ,
gl2_video_layout_led_seg ,
gl2_video_layout_layer_end
} ;
static const video_layout_render_interface_t * gl2_get_video_layout_render_interface ( void * data )
{
return & gl2_video_layout_render_interface ;
}
# endif /* HAVE_VIDEO_LAYOUT */
2019-02-06 19:43:31 +01:00
static bool gl2_frame ( void * data , const void * frame ,
2015-05-20 00:45:42 +02:00
unsigned frame_width , unsigned frame_height ,
2015-08-03 23:01:07 +02:00
uint64_t frame_count ,
2017-01-09 14:25:59 +01:00
unsigned pitch , const char * msg ,
2017-01-18 17:41:27 +01:00
video_frame_info_t * video_info )
2012-02-01 00:14:04 +01:00
{
2016-02-14 18:09:12 +01:00
video_shader_ctx_params_t params ;
2016-05-10 02:39:09 +02:00
struct video_tex_info feedback_info ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2019-02-07 23:54:33 +01:00
gl2_renderchain_data_t * chain = ( gl2_renderchain_data_t * ) gl - > renderchain_data ;
2020-03-07 00:58:06 +01:00
unsigned width = gl - > video_width ;
unsigned height = gl - > video_height ;
2020-03-09 15:40:14 +01:00
bool use_rgba = video_info - > use_rgba ;
bool statistics_show = video_info - > statistics_show ;
bool msg_bgcolor_enable = video_info - > msg_bgcolor_enable ;
2020-10-16 00:24:32 +02:00
# ifndef EMSCRIPTEN
2020-09-18 11:57:32 -04:00
unsigned black_frame_insertion = video_info - > black_frame_insertion ;
2020-10-16 00:24:32 +02:00
# endif
2020-03-09 15:40:14 +01:00
bool input_driver_nonblock_state = video_info - > input_driver_nonblock_state ;
bool hard_sync = video_info - > hard_sync ;
unsigned hard_sync_frames = video_info - > hard_sync_frames ;
struct font_params * osd_params = ( struct font_params * )
& video_info - > osd_stat_params ;
const char * stat_text = video_info - > stat_text ;
2020-08-03 16:33:54 +02:00
# ifdef HAVE_MENU
2020-05-19 16:20:43 +02:00
bool menu_is_alive = video_info - > menu_is_alive ;
2020-08-03 16:33:54 +02:00
# endif
# ifdef HAVE_GFX_WIDGETS
bool widgets_active = video_info - > widgets_active ;
# endif
# ifndef EMSCRIPTEN
bool runloop_is_slowmotion = video_info - > runloop_is_slowmotion ;
bool runloop_is_paused = video_info - > runloop_is_paused ;
# endif
2021-12-26 05:56:44 +02:00
bool overlay_behind_menu = video_info - > overlay_behind_menu ;
2015-01-10 03:48:03 +01:00
2017-11-08 15:52:23 +01:00
if ( ! gl )
2016-02-13 21:15:18 +01:00
return false ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2013-06-22 15:06:56 +02:00
2019-08-12 22:04:27 +02:00
# ifndef HAVE_OPENGLES
2019-02-03 00:07:53 +01:00
if ( gl - > core_context_in_use )
2019-08-12 22:04:27 +02:00
glBindVertexArray ( chain - > vao ) ;
# endif
2011-05-26 12:53:24 +02:00
2019-03-18 15:52:21 +01:00
gl - > shader - > use ( gl , gl - > shader_data , 1 , true ) ;
2011-05-26 12:53:24 +02:00
2014-10-01 23:50:58 +02:00
# ifdef IOS
/* Apparently the viewport is lost each frame, thanks Apple. */
2020-03-06 02:25:28 +01:00
gl2_set_viewport ( gl , width , height , false , true ) ;
2013-04-10 20:42:54 +02:00
# endif
2014-10-01 20:06:40 +02:00
/* Render to texture in first pass. */
2011-03-06 19:56:35 +01:00
if ( gl - > fbo_inited )
{
2019-02-03 00:07:53 +01:00
gl2_renderchain_recompute_pass_sizes (
2019-02-07 23:54:33 +01:00
gl , chain ,
2019-02-07 23:16:25 +01:00
frame_width , frame_height ,
2019-02-03 00:07:53 +01:00
gl - > vp_out_width , gl - > vp_out_height ) ;
2017-11-07 11:01:30 +01:00
2020-03-07 00:58:06 +01:00
gl2_renderchain_start_render ( gl , chain ) ;
2012-02-01 00:14:04 +01:00
}
2011-05-23 19:57:52 +02:00
2012-02-01 00:14:04 +01:00
if ( gl - > should_resize )
{
2020-07-09 05:36:29 +02:00
if ( gl - > ctx_driver - > set_resize )
2020-07-09 07:46:40 +02:00
gl - > ctx_driver - > set_resize ( gl - > ctx_data ,
2019-08-12 22:04:27 +02:00
width , height ) ;
gl - > should_resize = false ;
2011-05-23 19:57:52 +02:00
2014-10-01 19:34:55 +02:00
if ( gl - > fbo_inited )
{
2019-08-14 16:40:47 +02:00
/* On resize, we might have to recreate our FBOs
* due to " Viewport " scale , and set a new viewport . */
unsigned i ;
/* Check if we have to recreate our FBO textures. */
for ( i = 0 ; i < ( unsigned ) chain - > fbo_pass ; i + + )
{
struct video_fbo_rect * fbo_rect = & gl - > fbo_rect [ i ] ;
if ( fbo_rect )
{
unsigned img_width = fbo_rect - > max_img_width ;
unsigned img_height = fbo_rect - > max_img_height ;
if ( ( img_width > fbo_rect - > width ) | |
( img_height > fbo_rect - > height ) )
{
/* Check proactively since we might suddently
* get sizes of tex_w width or tex_h height . */
unsigned max = img_width > img_height ? img_width : img_height ;
unsigned pow2_size = next_pow2 ( max ) ;
bool update_feedback = gl - > fbo_feedback_enable
& & ( unsigned ) i = = gl - > fbo_feedback_pass ;
fbo_rect - > width = pow2_size ;
fbo_rect - > height = pow2_size ;
gl2_recreate_fbo ( fbo_rect , chain - > fbo [ i ] , & chain - > fbo_texture [ i ] ) ;
/* Update feedback texture in-place so we avoid having to
* juggle two different fbo_rect structs since they get updated here . */
if ( update_feedback )
{
if ( gl2_recreate_fbo ( fbo_rect , gl - > fbo_feedback ,
& gl - > fbo_feedback_texture ) )
{
/* Make sure the feedback textures are cleared
* so we don ' t feedback noise . */
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
}
}
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " [GL]: Recreating FBO texture #%d: %ux%u. \n " ,
2019-08-14 16:40:47 +02:00
i , fbo_rect - > width , fbo_rect - > height ) ;
}
}
}
2014-10-01 19:34:55 +02:00
2016-09-17 20:57:17 -03:00
/* Go back to what we're supposed to do,
2014-10-01 19:34:55 +02:00
* render to FBO # 0. */
2020-03-07 00:58:06 +01:00
gl2_renderchain_start_render ( gl , chain ) ;
2014-10-01 19:34:55 +02:00
}
else
2020-03-05 21:45:02 +01:00
gl2_set_viewport ( gl , width , height , false , true ) ;
2019-04-03 05:04:17 +01:00
# ifdef HAVE_VIDEO_LAYOUT
gl - > video_layout_resize = true ;
# endif
2012-02-01 00:14:04 +01:00
}
2011-03-12 16:33:01 +01:00
2019-04-03 05:04:17 +01:00
# ifdef HAVE_VIDEO_LAYOUT
2020-03-07 00:58:06 +01:00
gl2_video_layout_viewport ( gl ) ;
2019-04-03 05:04:17 +01:00
# endif
2016-04-16 07:16:32 +02:00
if ( frame )
gl - > tex_index = ( ( gl - > tex_index + 1 ) % gl - > textures ) ;
2014-10-01 18:23:02 +02:00
glBindTexture ( GL_TEXTURE_2D , gl - > texture [ gl - > tex_index ] ) ;
2012-12-10 13:02:59 +01:00
2014-10-01 18:23:02 +02:00
/* Can be NULL for frame dupe / NULL render. */
2017-12-11 23:55:31 -08:00
if ( frame )
2014-10-01 18:23:02 +02:00
{
2013-09-07 15:04:40 +02:00
if ( ! gl - > hw_render_fbo_init )
2013-03-27 16:15:15 +01:00
{
2019-02-06 19:43:31 +01:00
gl2_update_input_size ( gl , frame_width , frame_height , pitch , true ) ;
2017-11-08 16:38:56 +01:00
2020-03-09 15:40:14 +01:00
gl2_renderchain_copy_frame ( gl , chain , use_rgba ,
frame , frame_width , frame_height , pitch ) ;
2013-03-27 16:15:15 +01:00
}
2011-05-23 19:57:52 +02:00
2016-09-17 20:57:17 -03:00
/* No point regenerating mipmaps
2014-10-01 18:23:02 +02:00
* if there are no new frames . */
2017-11-08 00:49:01 +01:00
if ( gl - > tex_mipmap & & gl - > have_mipmap )
2014-10-01 18:23:02 +02:00
glGenerateMipmap ( GL_TEXTURE_2D ) ;
}
2014-05-11 13:13:38 +02:00
2016-09-17 20:57:17 -03:00
/* Have to reset rendering state which libretro core
2014-10-01 18:23:02 +02:00
* could easily have overridden . */
2013-09-07 15:04:40 +02:00
if ( gl - > hw_render_fbo_init )
{
2019-02-06 19:43:31 +01:00
gl2_update_input_size ( gl , frame_width , frame_height , pitch , false ) ;
2013-09-07 15:04:40 +02:00
if ( ! gl - > fbo_inited )
{
2019-02-03 00:07:53 +01:00
gl2_renderchain_bind_backbuffer ( ) ;
2020-03-05 21:45:02 +01:00
gl2_set_viewport ( gl , width , height , false , true ) ;
2013-09-07 15:04:40 +02:00
}
2019-02-03 00:07:53 +01:00
gl2_renderchain_restore_default_state ( gl ) ;
2017-11-08 16:20:55 +01:00
2013-03-29 14:11:53 +01:00
glDisable ( GL_STENCIL_TEST ) ;
2013-07-07 10:35:13 +02:00
glDisable ( GL_BLEND ) ;
2013-05-22 21:41:10 +02:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2014-04-17 15:32:36 +02:00
glBlendEquation ( GL_FUNC_ADD ) ;
2013-03-28 12:13:41 +01:00
glClearColor ( 0.0f , 0.0f , 0.0f , 1.0f ) ;
}
2014-10-01 20:37:52 +02:00
gl - > tex_info . tex = gl - > texture [ gl - > tex_index ] ;
2015-05-20 00:45:42 +02:00
gl - > tex_info . input_size [ 0 ] = frame_width ;
gl - > tex_info . input_size [ 1 ] = frame_height ;
2014-10-01 20:37:52 +02:00
gl - > tex_info . tex_size [ 0 ] = gl - > tex_w ;
gl - > tex_info . tex_size [ 1 ] = gl - > tex_h ;
2012-12-10 13:18:10 +01:00
2015-09-21 11:50:02 +02:00
feedback_info = gl - > tex_info ;
2015-08-30 18:37:41 +02:00
if ( gl - > fbo_feedback_enable )
{
2017-12-11 23:55:31 -08:00
const struct video_fbo_rect
2017-11-08 18:31:17 +01:00
* rect = & gl - > fbo_rect [ gl - > fbo_feedback_pass ] ;
2016-03-24 03:32:00 +01:00
GLfloat xamt = ( GLfloat ) rect - > img_width / rect - > width ;
GLfloat yamt = ( GLfloat ) rect - > img_height / rect - > height ;
2015-08-30 18:37:41 +02:00
2016-03-24 03:32:00 +01:00
feedback_info . tex = gl - > fbo_feedback_texture ;
feedback_info . input_size [ 0 ] = rect - > img_width ;
feedback_info . input_size [ 1 ] = rect - > img_height ;
feedback_info . tex_size [ 0 ] = rect - > width ;
feedback_info . tex_size [ 1 ] = rect - > height ;
2015-08-30 18:37:41 +02:00
2020-09-01 19:54:41 +02:00
SET_TEXTURE_COORDS ( feedback_info . coord , xamt , yamt ) ;
2015-08-30 18:37:41 +02:00
}
2012-02-01 00:14:04 +01:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2014-08-27 22:40:19 +01:00
2016-02-14 18:09:12 +01:00
params . data = gl ;
params . width = frame_width ;
params . height = frame_height ;
params . tex_width = gl - > tex_w ;
params . tex_height = gl - > tex_h ;
params . out_width = gl - > vp . width ;
params . out_height = gl - > vp . height ;
params . frame_counter = ( unsigned int ) frame_count ;
params . info = & gl - > tex_info ;
params . prev_info = gl - > prev_info ;
params . feedback_info = & feedback_info ;
params . fbo_info = NULL ;
params . fbo_info_cnt = 0 ;
2019-02-06 19:49:45 +01:00
gl - > shader - > set_params ( & params , gl - > shader_data ) ;
2011-05-23 19:57:52 +02:00
2017-11-08 18:31:17 +01:00
gl - > coords . vertices = 4 ;
2016-02-14 18:59:42 +01:00
2019-03-18 15:27:37 +01:00
gl - > shader - > set_coords ( gl - > shader_data , & gl - > coords ) ;
gl - > shader - > set_mvp ( gl - > shader_data , & gl - > mvp ) ;
2016-02-14 19:43:47 +01:00
2012-09-13 20:47:49 +02:00
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
2011-06-05 02:01:44 +02:00
2019-02-03 00:07:53 +01:00
if ( gl - > fbo_inited )
2019-04-03 05:04:17 +01:00
gl2_renderchain_render ( gl ,
2019-02-07 23:54:33 +01:00
chain ,
2017-01-09 15:14:16 +01:00
frame_count , & gl - > tex_info , & feedback_info ) ;
2011-03-06 16:52:49 +01:00
2016-08-02 00:42:03 +02:00
/* Set prev textures. */
2019-02-07 23:16:25 +01:00
gl2_renderchain_bind_prev_texture ( gl ,
2019-02-07 23:54:33 +01:00
chain , & gl - > tex_info ) ;
2012-12-10 13:18:10 +01:00
2019-04-03 05:04:17 +01:00
# ifdef HAVE_VIDEO_LAYOUT
2020-03-10 19:32:21 +01:00
gl2_video_layout_render ( gl ) ;
2019-04-03 05:04:17 +01:00
# endif
2021-12-26 05:56:44 +02:00
# ifdef HAVE_OVERLAY
if ( gl - > overlay_enable & & overlay_behind_menu )
gl2_render_overlay ( gl ) ;
# endif
2013-11-08 04:36:16 +01:00
# if defined(HAVE_MENU)
2015-03-22 05:27:19 +01:00
if ( gl - > menu_texture_enable )
2015-07-01 18:46:39 -03:00
{
2020-05-19 16:20:43 +02:00
menu_driver_frame ( menu_is_alive , video_info ) ;
2015-07-01 18:46:39 -03:00
2017-11-16 14:01:20 +01:00
if ( gl - > menu_texture )
2020-03-07 00:58:06 +01:00
gl2_draw_texture ( gl ) ;
2015-07-01 18:46:39 -03:00
}
2020-03-09 15:40:14 +01:00
else if ( statistics_show )
2018-03-23 17:43:49 +01:00
{
if ( osd_params )
2020-03-10 03:24:59 +01:00
font_driver_render_msg ( gl , stat_text ,
2020-03-09 15:40:14 +01:00
( const struct font_params * ) osd_params , NULL ) ;
2018-03-23 17:43:49 +01:00
}
2013-02-27 20:20:29 -05:00
# endif
2019-02-17 18:51:19 -05:00
# ifdef HAVE_OVERLAY
2021-12-26 05:56:44 +02:00
if ( gl - > overlay_enable & & ! overlay_behind_menu )
2020-03-07 00:58:06 +01:00
gl2_render_overlay ( gl ) ;
2019-02-17 18:51:19 -05:00
# endif
2020-02-17 21:28:42 +01:00
# ifdef HAVE_GFX_WIDGETS
2020-08-03 16:33:54 +02:00
if ( widgets_active )
2020-06-08 05:45:15 +02:00
gfx_widgets_frame ( video_info ) ;
2019-05-11 06:26:40 +02:00
# endif
2017-08-31 11:59:23 -04:00
if ( ! string_is_empty ( msg ) )
2017-10-04 00:04:17 -04:00
{
2020-03-09 15:40:14 +01:00
if ( msg_bgcolor_enable )
2020-03-07 00:58:06 +01:00
gl2_render_osd_background ( gl , msg ) ;
2020-03-10 03:24:59 +01:00
font_driver_render_msg ( gl , msg , NULL , NULL ) ;
2017-10-04 00:04:17 -04:00
}
2011-01-23 00:27:20 +01:00
2020-03-28 05:36:31 +01:00
if ( gl - > ctx_driver - > update_window_title )
2020-07-09 07:46:40 +02:00
gl - > ctx_driver - > update_window_title ( gl - > ctx_data ) ;
2019-11-19 22:48:35 +01:00
2014-10-01 23:50:58 +02:00
/* Reset state which could easily mess up libretro core. */
2013-03-28 12:13:41 +01:00
if ( gl - > hw_render_fbo_init )
{
2019-03-18 15:52:21 +01:00
gl - > shader - > use ( gl , gl - > shader_data , 0 , true ) ;
2013-03-28 12:13:41 +01:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
2014-10-01 23:50:58 +02:00
/* Screenshots. */
2014-02-06 21:35:57 +01:00
if ( gl - > readback_buffer_screenshot )
2019-02-03 00:07:53 +01:00
gl2_renderchain_readback ( gl ,
2019-02-07 23:54:33 +01:00
chain ,
2019-02-03 00:07:53 +01:00
4 , GL_RGBA , GL_UNSIGNED_BYTE ,
gl - > readback_buffer_screenshot ) ;
2017-11-08 16:53:43 +01:00
2014-10-01 23:50:58 +02:00
/* Don't readback if we're in menu mode. */
2017-11-08 16:53:43 +01:00
else if ( gl - > pbo_readback_enable )
# ifdef HAVE_MENU
/* Don't readback if we're in menu mode. */
if ( ! gl - > menu_texture_enable )
2014-02-06 21:35:57 +01:00
# endif
2019-02-06 19:43:31 +01:00
gl2_pbo_async_readback ( gl ) ;
2015-09-26 12:57:52 +02:00
2020-09-18 11:57:32 -04:00
if ( gl - > ctx_driver - > swap_buffers )
gl - > ctx_driver - > swap_buffers ( gl - > ctx_data ) ;
/* Emscripten has to do black frame insertion in its main loop */
2018-01-20 13:01:24 -06:00
# ifndef EMSCRIPTEN
2020-08-03 16:33:54 +02:00
/* Disable BFI during fast forward, slow-motion,
* and pause to prevent flicker . */
2020-09-18 11:57:32 -04:00
if (
2020-08-03 16:33:54 +02:00
black_frame_insertion
& & ! input_driver_nonblock_state
& & ! runloop_is_slowmotion
2020-09-18 11:57:32 -04:00
& & ! runloop_is_paused
& & ! gl - > menu_texture_enable )
{
2020-09-19 13:28:21 -04:00
unsigned n ;
for ( n = 0 ; n < black_frame_insertion ; + + n )
2020-09-18 11:57:32 -04:00
{
glClearColor ( 0.0f , 0.0f , 0.0f , 1.0f ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
if ( gl - > ctx_driver - > swap_buffers )
gl - > ctx_driver - > swap_buffers ( gl - > ctx_data ) ;
}
}
# endif
2010-05-28 02:45:18 +02:00
2020-08-03 16:33:54 +02:00
/* check if we are fast forwarding or in menu,
* if we are ignore hard sync */
2018-05-17 17:24:10 +02:00
if ( gl - > have_sync
2020-03-09 15:40:14 +01:00
& & hard_sync
& & ! input_driver_nonblock_state
2021-11-20 02:20:53 +01:00
)
2013-05-03 14:04:29 +02:00
{
glClear ( GL_COLOR_BUFFER_BIT ) ;
2013-05-26 13:43:24 +02:00
2019-02-07 23:54:33 +01:00
gl2_renderchain_fence_iterate ( gl , chain ,
2020-03-09 15:40:14 +01:00
hard_sync_frames ) ;
2013-05-03 14:04:29 +02:00
}
2019-08-12 22:04:27 +02:00
# ifndef HAVE_OPENGLES
2019-02-03 00:07:53 +01:00
if ( gl - > core_context_in_use )
2019-08-12 22:04:27 +02:00
glBindVertexArray ( 0 ) ;
# endif
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2010-05-28 02:45:18 +02:00
return true ;
}
2021-09-26 17:42:12 +02:00
static void gl2_destroy_resources ( gl2_t * gl )
2016-05-16 05:47:34 +02:00
{
if ( gl )
{
if ( gl - > empty_buf )
free ( gl - > empty_buf ) ;
if ( gl - > conv_buffer )
free ( gl - > conv_buffer ) ;
free ( gl ) ;
}
2016-09-05 07:04:56 +02:00
gl_query_core_context_unset ( ) ;
2016-05-16 05:47:34 +02:00
}
2021-09-26 17:42:12 +02:00
static void gl2_deinit_chain ( gl2_t * gl )
2017-11-07 11:01:30 +01:00
{
2019-02-03 00:07:53 +01:00
if ( ! gl )
2017-11-07 11:01:30 +01:00
return ;
2019-02-03 00:07:53 +01:00
if ( gl - > renderchain_data )
free ( gl - > renderchain_data ) ;
2017-11-07 11:01:30 +01:00
gl - > renderchain_data = NULL ;
}
2019-02-06 19:43:31 +01:00
static void gl2_free ( void * data )
2010-05-28 02:45:18 +02:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2014-05-28 23:32:14 +02:00
if ( ! gl )
2012-05-27 22:39:29 +02:00
return ;
2019-04-03 05:04:17 +01:00
# ifdef HAVE_VIDEO_LAYOUT
gl2_video_layout_free ( gl ) ;
# endif
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2011-01-05 17:22:12 +01:00
2013-05-26 13:43:24 +02:00
if ( gl - > have_sync )
2019-04-03 05:04:17 +01:00
gl2_renderchain_fence_free ( gl ,
2019-02-07 23:16:25 +01:00
( gl2_renderchain_data_t * )
gl - > renderchain_data ) ;
2013-05-26 13:43:24 +02:00
2016-10-18 20:07:00 -03:00
font_driver_free_osd ( ) ;
2019-02-05 02:12:42 +01:00
2019-02-06 19:49:45 +01:00
gl - > shader - > deinit ( gl - > shader_data ) ;
2012-09-13 17:05:48 +02:00
2013-07-06 22:10:09 +02:00
glDeleteTextures ( gl - > textures , gl - > texture ) ;
2012-12-23 18:36:58 +01:00
2013-11-08 04:36:16 +01:00
# if defined(HAVE_MENU)
2014-06-10 02:15:29 +02:00
if ( gl - > menu_texture )
glDeleteTextures ( 1 , & gl - > menu_texture ) ;
2013-02-27 20:20:29 -05:00
# endif
2012-12-23 18:36:58 +01:00
# ifdef HAVE_OVERLAY
2019-02-06 19:43:31 +01:00
gl2_free_overlay ( gl ) ;
2012-12-23 18:36:58 +01:00
# endif
2011-03-23 23:48:13 +01:00
2012-09-11 09:55:03 +02:00
# if defined(HAVE_PSGL)
2012-05-26 15:45:00 +02:00
glBindBuffer ( GL_TEXTURE_REFERENCE_BUFFER_SCE , 0 ) ;
glDeleteBuffers ( 1 , & gl - > pbo ) ;
# endif
2013-01-03 01:18:19 +01:00
scaler_ctx_gen_reset ( & gl - > scaler ) ;
2012-11-21 16:24:28 +01:00
if ( gl - > pbo_readback_enable )
2012-11-21 22:12:56 +01:00
{
2013-07-05 18:15:42 +02:00
glDeleteBuffers ( 4 , gl - > pbo_readback ) ;
2012-11-21 22:12:56 +01:00
scaler_ctx_gen_reset ( & gl - > pbo_readback_scaler ) ;
}
2012-11-21 16:24:28 +01:00
2019-08-12 22:04:27 +02:00
# ifndef HAVE_OPENGLES
2017-11-08 05:59:08 +01:00
if ( gl - > core_context_in_use )
2013-06-22 15:06:56 +02:00
{
2019-08-12 22:04:27 +02:00
gl2_renderchain_data_t * chain = ( gl2_renderchain_data_t * )
gl - > renderchain_data ;
glBindVertexArray ( 0 ) ;
glDeleteVertexArrays ( 1 , & chain - > vao ) ;
2013-06-22 15:06:56 +02:00
}
2019-08-12 22:04:27 +02:00
# endif
2013-06-22 15:06:56 +02:00
2019-02-07 23:16:25 +01:00
gl2_renderchain_deinit_fbo ( gl , ( gl2_renderchain_data_t * ) gl - > renderchain_data ) ;
gl2_renderchain_deinit_hw_render ( gl , ( gl2_renderchain_data_t * ) gl - > renderchain_data ) ;
2019-02-06 19:43:31 +01:00
gl2_deinit_chain ( gl ) ;
2017-11-11 13:55:05 -05:00
2020-08-03 00:35:07 +02:00
if ( gl - > ctx_driver & & gl - > ctx_driver - > destroy )
gl - > ctx_driver - > destroy ( gl - > ctx_data ) ;
2016-05-08 20:32:46 +02:00
video_context_driver_free ( ) ;
2015-05-02 22:37:27 +02:00
2019-02-06 19:43:31 +01:00
gl2_destroy_resources ( gl ) ;
2010-05-28 02:45:18 +02:00
}
2020-02-16 22:26:07 +01:00
static void gl2_set_nonblock_state (
void * data , bool state ,
bool adaptive_vsync_enabled ,
unsigned swap_interval )
2010-08-16 18:40:17 +02:00
{
2018-09-12 00:07:43 +02:00
int interval = 0 ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2014-05-29 00:30:48 +02:00
2014-10-01 16:59:43 +02:00
if ( ! gl )
return ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2016-02-13 20:45:45 +01:00
2016-03-24 03:32:00 +01:00
if ( ! state )
2020-02-16 22:26:07 +01:00
interval = swap_interval ;
2016-02-13 20:45:45 +01:00
2019-08-28 21:12:51 +02:00
if ( gl - > ctx_driver - > swap_interval )
{
if ( adaptive_vsync_enabled & & interval = = 1 )
interval = - 1 ;
gl - > ctx_driver - > swap_interval ( gl - > ctx_data , interval ) ;
}
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2010-08-16 18:40:17 +02:00
}
2021-09-26 17:42:12 +02:00
static bool gl2_resolve_extensions ( gl2_t * gl , const char * context_ident , const video_info_t * video )
2012-09-11 12:32:50 +02:00
{
2017-11-16 14:01:20 +01:00
settings_t * settings = config_get_ptr ( ) ;
2020-02-18 14:51:40 +01:00
bool video_hard_sync = settings - > bools . video_hard_sync ;
2017-11-08 16:20:55 +01:00
2017-11-08 16:49:42 +01:00
/* have_es2_compat - GL_RGB565 internal format support.
2016-09-17 20:57:17 -03:00
* Even though ES2 support is claimed , the format
2014-10-01 23:50:58 +02:00
* is not supported on older ATI catalyst drivers .
*
2016-09-17 20:57:17 -03:00
* The speed gain from using GL_RGB565 is worth
2014-10-01 23:50:58 +02:00
* adding some workarounds for .
2017-11-08 16:49:42 +01:00
*
* have_sync - Use ARB_sync to reduce latency .
2014-10-01 23:50:58 +02:00
*/
2017-11-08 16:49:42 +01:00
gl - > have_full_npot_support = gl_check_capability ( GL_CAPS_FULL_NPOT_SUPPORT ) ;
gl - > have_mipmap = gl_check_capability ( GL_CAPS_MIPMAP ) ;
gl - > have_es2_compat = gl_check_capability ( GL_CAPS_ES2_COMPAT ) ;
gl - > support_unpack_row_length = gl_check_capability ( GL_CAPS_UNPACK_ROW_LENGTH ) ;
gl - > have_sync = gl_check_capability ( GL_CAPS_SYNC ) ;
2013-06-22 15:06:56 +02:00
2020-02-18 14:51:40 +01:00
if ( gl - > have_sync & & video_hard_sync )
2013-05-03 14:04:29 +02:00
RARCH_LOG ( " [GL]: Using ARB_sync to reduce latency. \n " ) ;
2016-05-08 14:00:51 +02:00
video_driver_unset_rgba ( ) ;
2015-11-27 21:21:04 -03:00
2019-02-03 00:07:53 +01:00
gl2_renderchain_resolve_extensions ( gl ,
2019-02-07 23:16:25 +01:00
( gl2_renderchain_data_t * ) gl - > renderchain_data ,
context_ident , video ) ;
2017-12-04 12:43:22 +01:00
2017-11-08 16:49:42 +01:00
# if defined(HAVE_OPENGLES) && !defined(HAVE_PSGL)
2016-08-01 17:40:53 +02:00
if ( ! gl_check_capability ( GL_CAPS_BGRA8888 ) )
2012-09-29 20:06:48 +02:00
{
2016-05-08 14:10:28 +02:00
video_driver_set_rgba ( ) ;
2013-01-03 01:18:19 +01:00
RARCH_WARN ( " [GL]: GLES implementation does not have BGRA8888 extension. \n "
2021-02-18 18:33:47 +02:00
" [GL]: 32-bit path will require conversion. \n " ) ;
2012-09-29 20:06:48 +02:00
}
2016-08-01 17:40:53 +02:00
/* TODO/FIXME - No extensions for float FBO currently. */
2014-02-11 16:07:00 +11:00
# endif
2012-09-29 20:06:48 +02:00
2013-08-14 14:00:21 +02:00
# ifdef GL_DEBUG
2014-10-01 23:50:58 +02:00
/* Useful for debugging, but kinda obnoxious otherwise. */
2013-08-14 14:00:21 +02:00
RARCH_LOG ( " [GL]: Supported extensions: \n " ) ;
2016-08-01 17:40:53 +02:00
2017-11-08 05:59:08 +01:00
if ( gl - > core_context_in_use )
2013-08-14 14:00:21 +02:00
{
# ifdef GL_NUM_EXTENSIONS
GLint exts = 0 ;
glGetIntegerv ( GL_NUM_EXTENSIONS , & exts ) ;
for ( GLint i = 0 ; i < exts ; i + + )
{
const char * ext = ( const char * ) glGetStringi ( GL_EXTENSIONS , i ) ;
if ( ext )
RARCH_LOG ( " \t %s \n " , ext ) ;
}
# endif
}
else
{
const char * ext = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
2015-02-13 02:21:54 +01:00
2013-08-14 14:00:21 +02:00
if ( ext )
{
2015-01-11 19:52:02 +01:00
size_t i ;
2020-08-26 13:35:05 +02:00
struct string_list list = { 0 } ;
2015-01-11 19:52:02 +01:00
2020-08-26 13:35:05 +02:00
string_list_initialize ( & list ) ;
string_split_noalloc ( & list , ext , " " ) ;
for ( i = 0 ; i < list . size ; i + + )
RARCH_LOG ( " \t %s \n " , list . elems [ i ] . data ) ;
string_list_deinitialize ( & list ) ;
2013-08-14 14:00:21 +02:00
}
}
2012-09-23 11:54:51 +02:00
# endif
2012-09-15 15:17:34 +02:00
2012-09-11 12:32:50 +02:00
return true ;
}
2021-09-26 17:42:12 +02:00
static INLINE void gl2_set_texture_fmts ( gl2_t * gl , bool rgb32 )
2013-01-03 01:18:19 +01:00
{
2015-02-11 16:11:05 +01:00
gl - > internal_fmt = RARCH_GL_INTERNAL_FORMAT16 ;
gl - > texture_type = RARCH_GL_TEXTURE_TYPE16 ;
gl - > texture_fmt = RARCH_GL_FORMAT16 ;
gl - > base_size = sizeof ( uint16_t ) ;
2013-01-03 01:18:19 +01:00
2015-02-11 16:11:05 +01:00
if ( rgb32 )
2013-01-03 01:18:19 +01:00
{
2016-05-08 14:00:51 +02:00
bool use_rgba = video_driver_supports_rgba ( ) ;
2015-11-23 23:58:40 +01:00
2015-02-11 16:11:05 +01:00
gl - > internal_fmt = RARCH_GL_INTERNAL_FORMAT32 ;
gl - > texture_type = RARCH_GL_TEXTURE_TYPE32 ;
gl - > texture_fmt = RARCH_GL_FORMAT32 ;
gl - > base_size = sizeof ( uint32_t ) ;
2014-01-01 21:42:31 +01:00
2015-11-23 23:58:40 +01:00
if ( use_rgba )
2015-02-11 16:11:05 +01:00
{
gl - > internal_fmt = GL_RGBA ;
gl - > texture_type = GL_RGBA ;
}
}
2017-11-08 00:59:16 +01:00
# ifndef HAVE_OPENGLES
2015-02-11 16:11:05 +01:00
else if ( gl - > have_es2_compat )
2014-01-01 21:42:31 +01:00
{
RARCH_LOG ( " [GL]: Using GL_RGB565 for texture uploads. \n " ) ;
gl - > internal_fmt = RARCH_GL_INTERNAL_FORMAT16_565 ;
gl - > texture_type = RARCH_GL_TEXTURE_TYPE16_565 ;
2016-02-14 16:59:21 +01:00
gl - > texture_fmt = RARCH_GL_FORMAT16_565 ;
2014-01-01 21:42:31 +01:00
}
2017-11-08 00:59:16 +01:00
# endif
2013-01-03 01:18:19 +01:00
}
2021-09-26 17:42:12 +02:00
static bool gl2_init_pbo_readback ( gl2_t * gl )
2012-11-21 16:24:28 +01:00
{
2019-02-03 00:07:53 +01:00
# if !defined(HAVE_OPENGLES2) && !defined(HAVE_PSGL)
2017-09-09 00:20:39 +02:00
unsigned i ;
2012-11-21 16:24:28 +01:00
2013-07-05 18:15:42 +02:00
glGenBuffers ( 4 , gl - > pbo_readback ) ;
2017-11-08 18:48:01 +01:00
2013-10-22 21:26:33 +02:00
for ( i = 0 ; i < 4 ; i + + )
2012-11-21 16:24:28 +01:00
{
2019-02-03 00:07:53 +01:00
gl2_renderchain_bind_pbo ( gl - > pbo_readback [ i ] ) ;
gl2_renderchain_init_pbo ( gl - > vp . width *
gl - > vp . height * sizeof ( uint32_t ) , NULL ) ;
2012-11-21 16:24:28 +01:00
}
2019-02-03 00:07:53 +01:00
gl2_renderchain_unbind_pbo ( ) ;
2012-11-21 22:12:56 +01:00
2014-04-19 17:27:49 +02:00
# ifndef HAVE_OPENGLES3
2012-11-21 22:12:56 +01:00
{
2017-11-07 23:19:54 +01:00
struct scaler_ctx * scaler = & gl - > pbo_readback_scaler ;
scaler - > in_width = gl - > vp . width ;
scaler - > in_height = gl - > vp . height ;
scaler - > out_width = gl - > vp . width ;
scaler - > out_height = gl - > vp . height ;
scaler - > in_stride = gl - > vp . width * sizeof ( uint32_t ) ;
scaler - > out_stride = gl - > vp . width * 3 ;
scaler - > in_fmt = SCALER_FMT_ARGB8888 ;
scaler - > out_fmt = SCALER_FMT_BGR24 ;
scaler - > scaler_type = SCALER_TYPE_POINT ;
if ( ! scaler_ctx_gen_filter ( scaler ) )
{
gl - > pbo_readback_enable = false ;
RARCH_ERR ( " [GL]: Failed to initialize pixel conversion for PBO. \n " ) ;
glDeleteBuffers ( 4 , gl - > pbo_readback ) ;
2017-11-08 16:49:42 +01:00
return false ;
2017-11-07 23:19:54 +01:00
}
2012-11-21 22:12:56 +01:00
}
2014-04-19 17:27:49 +02:00
# endif
2017-11-08 16:49:42 +01:00
return true ;
2019-02-03 00:07:53 +01:00
# else
/* If none of these are bound, we have to assume
* we are not going to use PBOs */
return false ;
# endif
2012-11-21 16:24:28 +01:00
}
2021-09-26 17:42:12 +02:00
static const gfx_ctx_driver_t * gl2_get_context ( gl2_t * gl )
2013-02-23 14:49:49 +01:00
{
2018-10-14 08:13:05 +02:00
const gfx_ctx_driver_t * gfx_ctx = NULL ;
void * ctx_data = NULL ;
2016-05-05 02:07:33 +02:00
settings_t * settings = config_get_ptr ( ) ;
2016-08-01 17:46:02 +02:00
struct retro_hw_render_callback * hwr = video_driver_get_hw_context ( ) ;
unsigned major = hwr - > version_major ;
unsigned minor = hwr - > version_minor ;
2020-02-19 19:23:10 +01:00
bool video_shared_context = settings - > bools . video_shared_context ;
2013-02-23 14:49:49 +01:00
# ifdef HAVE_OPENGLES
2020-02-19 19:23:10 +01:00
enum gfx_ctx_api api = GFX_CTX_OPENGL_ES_API ;
2018-10-11 03:52:38 +02:00
if ( hwr - > context_type = = RETRO_HW_CONTEXT_OPENGLES3 )
2013-12-13 14:19:25 +01:00
{
2018-10-11 03:52:38 +02:00
major = 3 ;
minor = 0 ;
2013-12-13 14:19:25 +01:00
}
2013-02-23 14:49:49 +01:00
# else
2020-02-19 19:23:10 +01:00
enum gfx_ctx_api api = GFX_CTX_OPENGL_API ;
2013-02-23 14:49:49 +01:00
# endif
2020-03-07 17:34:35 +01:00
gl - > shared_context_use = video_shared_context
2018-10-11 03:52:38 +02:00
& & hwr - > context_type ! = RETRO_HW_CONTEXT_NONE ;
2014-04-19 16:59:26 +02:00
2018-10-11 03:52:38 +02:00
if ( ( libretro_get_shared_context ( ) )
& & ( hwr - > context_type ! = RETRO_HW_CONTEXT_NONE ) )
2020-03-07 17:34:35 +01:00
gl - > shared_context_use = true ;
2017-08-07 18:05:43 +02:00
2018-10-14 08:13:05 +02:00
gfx_ctx = video_context_driver_init_first ( gl ,
2017-11-08 16:00:37 +01:00
settings - > arrays . video_context_driver ,
2020-03-07 17:34:35 +01:00
api , major , minor , gl - > shared_context_use , & ctx_data ) ;
2018-10-14 08:13:05 +02:00
if ( ctx_data )
gl - > ctx_data = ctx_data ;
return gfx_ctx ;
2013-02-23 14:49:49 +01:00
}
2013-08-14 14:00:21 +02:00
# ifdef GL_DEBUG
2016-08-08 18:37:46 +02:00
# ifdef HAVE_GL_DEBUG_ES
2013-08-14 14:00:21 +02:00
# define DEBUG_CALLBACK_TYPE GL_APIENTRY
2014-10-01 23:50:58 +02:00
2014-04-21 14:37:43 +02:00
# define GL_DEBUG_SOURCE_API GL_DEBUG_SOURCE_API_KHR
# define GL_DEBUG_SOURCE_WINDOW_SYSTEM GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR
# define GL_DEBUG_SOURCE_SHADER_COMPILER GL_DEBUG_SOURCE_SHADER_COMPILER_KHR
# define GL_DEBUG_SOURCE_THIRD_PARTY GL_DEBUG_SOURCE_THIRD_PARTY_KHR
# define GL_DEBUG_SOURCE_APPLICATION GL_DEBUG_SOURCE_APPLICATION_KHR
# define GL_DEBUG_SOURCE_OTHER GL_DEBUG_SOURCE_OTHER_KHR
# define GL_DEBUG_TYPE_ERROR GL_DEBUG_TYPE_ERROR_KHR
# define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR
# define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR
# define GL_DEBUG_TYPE_PORTABILITY GL_DEBUG_TYPE_PORTABILITY_KHR
# define GL_DEBUG_TYPE_PERFORMANCE GL_DEBUG_TYPE_PERFORMANCE_KHR
# define GL_DEBUG_TYPE_MARKER GL_DEBUG_TYPE_MARKER_KHR
# define GL_DEBUG_TYPE_PUSH_GROUP GL_DEBUG_TYPE_PUSH_GROUP_KHR
# define GL_DEBUG_TYPE_POP_GROUP GL_DEBUG_TYPE_POP_GROUP_KHR
# define GL_DEBUG_TYPE_OTHER GL_DEBUG_TYPE_OTHER_KHR
# define GL_DEBUG_SEVERITY_HIGH GL_DEBUG_SEVERITY_HIGH_KHR
# define GL_DEBUG_SEVERITY_MEDIUM GL_DEBUG_SEVERITY_MEDIUM_KHR
# define GL_DEBUG_SEVERITY_LOW GL_DEBUG_SEVERITY_LOW_KHR
2013-08-14 14:00:21 +02:00
# else
# define DEBUG_CALLBACK_TYPE APIENTRY
# endif
2016-08-08 18:37:46 +02:00
2019-02-06 19:43:31 +01:00
static void DEBUG_CALLBACK_TYPE gl2_debug_cb ( GLenum source , GLenum type ,
2013-08-14 14:00:21 +02:00
GLuint id , GLenum severity , GLsizei length ,
const GLchar * message , void * userParam )
{
2015-06-13 02:49:29 +02:00
const char * src = NULL ;
2016-05-12 02:58:09 +02:00
const char * typestr = NULL ;
2013-08-14 14:00:21 +02:00
switch ( source )
{
2014-10-01 16:59:43 +02:00
case GL_DEBUG_SOURCE_API :
src = " API " ;
break ;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM :
src = " Window system " ;
break ;
case GL_DEBUG_SOURCE_SHADER_COMPILER :
src = " Shader compiler " ;
break ;
case GL_DEBUG_SOURCE_THIRD_PARTY :
src = " 3rd party " ;
break ;
case GL_DEBUG_SOURCE_APPLICATION :
src = " Application " ;
break ;
case GL_DEBUG_SOURCE_OTHER :
src = " Other " ;
break ;
default :
src = " Unknown " ;
break ;
2013-08-14 14:00:21 +02:00
}
switch ( type )
{
2014-10-01 16:59:43 +02:00
case GL_DEBUG_TYPE_ERROR :
typestr = " Error " ;
break ;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR :
typestr = " Deprecated behavior " ;
break ;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR :
typestr = " Undefined behavior " ;
break ;
case GL_DEBUG_TYPE_PORTABILITY :
typestr = " Portability " ;
break ;
case GL_DEBUG_TYPE_PERFORMANCE :
typestr = " Performance " ;
break ;
case GL_DEBUG_TYPE_MARKER :
typestr = " Marker " ;
break ;
case GL_DEBUG_TYPE_PUSH_GROUP :
typestr = " Push group " ;
break ;
case GL_DEBUG_TYPE_POP_GROUP :
typestr = " Pop group " ;
break ;
case GL_DEBUG_TYPE_OTHER :
typestr = " Other " ;
break ;
default :
typestr = " Unknown " ;
break ;
2013-08-14 14:00:21 +02:00
}
switch ( severity )
{
case GL_DEBUG_SEVERITY_HIGH :
RARCH_ERR ( " [GL debug (High, %s, %s)]: %s \n " , src , typestr , message ) ;
break ;
case GL_DEBUG_SEVERITY_MEDIUM :
RARCH_WARN ( " [GL debug (Medium, %s, %s)]: %s \n " , src , typestr , message ) ;
break ;
case GL_DEBUG_SEVERITY_LOW :
RARCH_LOG ( " [GL debug (Low, %s, %s)]: %s \n " , src , typestr , message ) ;
break ;
}
}
2021-09-26 17:42:12 +02:00
static void gl2_begin_debug ( gl2_t * gl )
2013-08-14 14:00:21 +02:00
{
2016-08-01 16:06:19 +02:00
if ( gl_check_capability ( GL_CAPS_DEBUG ) )
2013-08-14 14:00:21 +02:00
{
2016-08-08 18:37:46 +02:00
# ifdef HAVE_GL_DEBUG_ES
2019-02-09 04:07:12 +01:00
glDebugMessageCallbackKHR ( gl2_debug_cb , gl ) ;
2014-04-21 14:37:43 +02:00
glDebugMessageControlKHR ( GL_DONT_CARE , GL_DONT_CARE , GL_DONT_CARE , 0 , NULL , GL_TRUE ) ;
glEnable ( GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR ) ;
# else
2019-02-09 04:07:12 +01:00
glDebugMessageCallback ( gl2_debug_cb , gl ) ;
2013-08-14 14:00:21 +02:00
glDebugMessageControl ( GL_DONT_CARE , GL_DONT_CARE , GL_DONT_CARE , 0 , NULL , GL_TRUE ) ;
glEnable ( GL_DEBUG_OUTPUT_SYNCHRONOUS ) ;
2014-04-21 14:37:43 +02:00
# endif
2013-08-14 14:00:21 +02:00
}
else
2017-03-24 01:28:58 +01:00
RARCH_ERR ( " [GL]: Neither GL_KHR_debug nor GL_ARB_debug_output are implemented. Cannot start GL debugging. \n " ) ;
2013-08-14 14:00:21 +02:00
}
# endif
2019-02-06 19:43:31 +01:00
static bool renderchain_gl2_init_first ( void * * renderchain_handle )
2018-02-16 11:24:10 +01:00
{
2019-02-03 00:07:53 +01:00
gl2_renderchain_data_t * data = ( gl2_renderchain_data_t * ) calloc ( 1 , sizeof ( * data ) ) ;
2018-02-16 11:24:10 +01:00
2019-02-03 00:07:53 +01:00
if ( ! data )
return false ;
2018-02-16 11:24:10 +01:00
2019-02-03 00:07:53 +01:00
* renderchain_handle = data ;
return true ;
2018-02-16 11:24:10 +01:00
}
2016-05-16 05:47:34 +02:00
2019-02-06 19:43:31 +01:00
static void * gl2_init ( const video_info_t * video ,
2019-07-27 02:21:24 +02:00
input_driver_t * * input , void * * input_data )
2010-05-28 02:45:18 +02:00
{
2019-02-03 05:41:43 +01:00
enum gfx_wrap_type wrap_type ;
2016-03-29 15:28:13 +02:00
unsigned full_x , full_y ;
2016-02-14 19:30:48 +01:00
video_shader_ctx_info_t shader_info ;
2017-11-08 16:49:42 +01:00
settings_t * settings = config_get_ptr ( ) ;
2020-03-02 20:24:00 +01:00
bool video_gpu_record = settings - > bools . video_gpu_record ;
2018-09-12 00:07:43 +02:00
int interval = 0 ;
unsigned mip_level = 0 ;
2020-07-27 14:33:21 +02:00
unsigned mode_width = 0 ;
unsigned mode_height = 0 ;
2016-03-04 20:49:55 +01:00
unsigned win_width = 0 ;
unsigned win_height = 0 ;
2017-04-24 12:25:14 +02:00
unsigned temp_width = 0 ;
unsigned temp_height = 0 ;
2016-03-04 20:49:55 +01:00
bool force_smooth = false ;
const char * vendor = NULL ;
const char * renderer = NULL ;
const char * version = NULL ;
struct retro_hw_render_callback * hwr = NULL ;
2016-09-05 07:21:47 +02:00
char * error_string = NULL ;
2021-11-10 02:34:04 +01:00
recording_state_t * recording_st = recording_state_get_ptr ( ) ;
gl2_t * gl = ( gl2_t * ) calloc ( 1 , sizeof ( gl2_t ) ) ;
2019-02-06 19:43:31 +01:00
const gfx_ctx_driver_t * ctx_driver = gl2_get_context ( gl ) ;
2019-01-19 12:12:43 -08:00
2016-02-13 16:33:38 +01:00
if ( ! gl | | ! ctx_driver )
2015-04-10 06:17:04 +02:00
goto error ;
2011-01-06 18:34:11 +01:00
2016-05-08 20:40:42 +02:00
video_context_driver_set ( ( const gfx_ctx_driver_t * ) ctx_driver ) ;
2015-11-23 21:20:21 +01:00
2018-10-14 08:22:26 +02:00
gl - > ctx_driver = ctx_driver ;
2017-11-08 16:49:42 +01:00
gl - > video_info = * video ;
2013-07-06 22:10:09 +02:00
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " [GL]: Found GL context: \" %s \" . \n " , ctx_driver - > ident ) ;
2012-09-25 01:26:22 +02:00
2020-07-27 14:33:21 +02:00
if ( gl - > ctx_driver - > get_video_size )
gl - > ctx_driver - > get_video_size ( gl - > ctx_data ,
& mode_width , & mode_height ) ;
2019-12-28 21:21:57 -05:00
# if defined(DINGUX)
2020-07-27 14:33:21 +02:00
mode_width = 320 ;
mode_height = 240 ;
2019-12-28 21:21:57 -05:00
# endif
2020-07-27 14:33:21 +02:00
full_x = mode_width ;
full_y = mode_height ;
2017-11-08 18:31:17 +01:00
interval = 0 ;
2016-02-14 02:26:20 +01:00
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " [GL]: Detecting screen resolution: %ux%u. \n " , full_x , full_y ) ;
2011-02-28 16:59:31 +01:00
2017-11-08 18:31:17 +01:00
if ( video - > vsync )
interval = video - > swap_interval ;
2016-02-13 20:45:45 +01:00
2019-08-28 21:12:51 +02:00
if ( gl - > ctx_driver - > swap_interval )
{
bool adaptive_vsync_enabled = video_driver_test_all_flags (
GFX_CTX_FLAGS_ADAPTIVE_VSYNC ) & & video - > adaptive_vsync ;
if ( adaptive_vsync_enabled & & interval = = 1 )
interval = - 1 ;
gl - > ctx_driver - > swap_interval ( gl - > ctx_data , interval ) ;
}
2011-01-06 18:34:11 +01:00
2017-11-08 18:31:17 +01:00
win_width = video - > width ;
win_height = video - > height ;
2014-10-01 16:59:43 +02:00
2011-09-13 18:50:40 +02:00
if ( video - > fullscreen & & ( win_width = = 0 ) & & ( win_height = = 0 ) )
{
2016-03-29 15:28:13 +02:00
win_width = full_x ;
win_height = full_y ;
2011-09-13 18:50:40 +02:00
}
2020-07-27 11:08:34 +02:00
if ( ! gl - > ctx_driver - > set_video_mode
| | ! gl - > ctx_driver - > set_video_mode ( gl - > ctx_data ,
win_width , win_height , video - > fullscreen ) )
2015-04-10 06:17:04 +02:00
goto error ;
2019-03-11 19:16:59 -04:00
# if defined(__APPLE__) && !defined(IOS)
2019-03-12 21:47:35 +01:00
/* This is a hack for now to work around a very annoying
* issue that currently eludes us . */
2020-07-27 11:08:34 +02:00
if ( ! gl - > ctx_driver - > set_video_mode
| | ! gl - > ctx_driver - > set_video_mode ( gl - > ctx_data ,
win_width , win_height , video - > fullscreen ) )
2019-03-11 19:16:59 -04:00
goto error ;
# endif
2011-01-11 22:33:28 +01:00
2018-09-27 00:52:06 +02:00
# if !defined(RARCH_CONSOLE) || defined(HAVE_LIBNX)
rglgen_resolve_symbols ( ctx_driver - > get_proc_address ) ;
# endif
2014-10-01 23:50:58 +02:00
/* Clear out potential error flags in case we use cached context. */
2016-09-17 20:57:17 -03:00
glGetError ( ) ;
2013-08-14 14:57:39 +02:00
2015-01-10 03:48:03 +01:00
vendor = ( const char * ) glGetString ( GL_VENDOR ) ;
renderer = ( const char * ) glGetString ( GL_RENDERER ) ;
version = ( const char * ) glGetString ( GL_VERSION ) ;
2013-07-13 01:46:57 +02:00
2015-01-10 03:48:03 +01:00
RARCH_LOG ( " [GL]: Vendor: %s, Renderer: %s. \n " , vendor , renderer ) ;
2013-08-16 10:18:58 +02:00
RARCH_LOG ( " [GL]: Version: %s. \n " , version ) ;
2019-01-19 12:12:43 -08:00
if ( string_is_equal ( ctx_driver - > ident , " null " ) )
goto error ;
2015-12-26 07:59:15 +01:00
if ( ! string_is_empty ( version ) )
2015-12-13 14:55:19 +01:00
sscanf ( version , " %d.%d " , & gl - > version_major , & gl - > version_minor ) ;
2019-03-07 19:17:54 -05:00
{
char device_str [ 128 ] ;
device_str [ 0 ] = ' \0 ' ;
2020-03-18 19:54:13 +01:00
if ( ! string_is_empty ( vendor ) )
{
strlcpy ( device_str , vendor , sizeof ( device_str ) ) ;
strlcat ( device_str , " " , sizeof ( device_str ) ) ;
}
if ( ! string_is_empty ( renderer ) )
strlcat ( device_str , renderer , sizeof ( device_str ) ) ;
2019-03-07 19:17:54 -05:00
video_driver_set_gpu_device_string ( device_str ) ;
2020-03-18 19:54:13 +01:00
if ( ! string_is_empty ( version ) )
video_driver_set_gpu_api_version_string ( version ) ;
2019-03-07 19:17:54 -05:00
}
2019-01-31 09:48:10 -05:00
# ifdef _WIN32
2021-09-28 00:50:48 +02:00
if ( string_is_equal ( vendor , " Microsoft Corporation " ) )
2019-01-31 09:48:10 -05:00
if ( string_is_equal ( renderer , " GDI Generic " ) )
2019-02-21 21:48:58 +01:00
# ifdef HAVE_OPENGL1
2021-09-28 00:50:48 +02:00
video_driver_force_fallback ( " gl1 " ) ;
2019-02-21 21:48:58 +01:00
# else
2021-09-28 00:50:48 +02:00
video_driver_force_fallback ( " gdi " ) ;
2019-02-21 21:48:58 +01:00
# endif
2022-01-30 09:30:39 +01:00
# endif
# if defined(__APPLE__) && defined(__ppc__)
if ( gl - > version_major = = 1 )
video_driver_force_fallback ( " gl1 " ) ;
2019-01-31 09:48:10 -05:00
# endif
2017-11-11 13:43:19 -05:00
hwr = video_driver_get_hw_context ( ) ;
2018-10-09 20:42:47 +02:00
if ( hwr - > context_type = = RETRO_HW_CONTEXT_OPENGL_CORE )
2017-11-11 13:43:19 -05:00
{
2018-10-11 03:52:38 +02:00
gl_query_core_context_set ( true ) ;
gl - > core_context_in_use = true ;
2018-10-10 18:24:41 +02:00
2021-03-24 00:25:24 +01:00
if ( hwr - > context_type = = RETRO_HW_CONTEXT_OPENGL_CORE )
{
/* Ensure that the rest of the frontend knows we have a core context */
gfx_ctx_flags_t flags ;
flags . flags = 0 ;
BIT32_SET ( flags . flags , GFX_CTX_FLAGS_GL_CORE_CONTEXT ) ;
video_context_driver_set_flags ( & flags ) ;
}
2018-10-11 03:52:38 +02:00
RARCH_LOG ( " [GL]: Using Core GL context, setting up VAO... \n " ) ;
if ( ! gl_check_capability ( GL_CAPS_VAO ) )
{
RARCH_ERR ( " [GL]: Failed to initialize VAOs. \n " ) ;
goto error ;
2017-11-11 13:43:19 -05:00
}
}
2019-02-06 19:43:31 +01:00
if ( ! renderchain_gl2_init_first ( & gl - > renderchain_data ) )
2017-11-11 13:43:19 -05:00
{
2018-08-17 07:49:25 -04:00
RARCH_ERR ( " [GL]: Renderchain could not be initialized. \n " ) ;
2017-11-13 09:11:09 +01:00
goto error ;
2017-11-11 13:43:19 -05:00
}
2019-02-03 00:07:53 +01:00
gl2_renderchain_restore_default_state ( gl ) ;
2017-11-11 13:43:19 -05:00
2019-08-12 22:04:27 +02:00
# ifndef HAVE_OPENGLES
2018-10-09 20:42:47 +02:00
if ( hwr - > context_type = = RETRO_HW_CONTEXT_OPENGL_CORE )
2019-08-12 22:04:27 +02:00
{
gl2_renderchain_data_t * chain = ( gl2_renderchain_data_t * )
gl - > renderchain_data ;
glGenVertexArrays ( 1 , & chain - > vao ) ;
}
# endif
2017-11-11 13:43:19 -05:00
2011-03-12 19:09:25 +01:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2014-04-17 15:32:36 +02:00
glBlendEquation ( GL_FUNC_ADD ) ;
2011-03-12 15:30:57 +01:00
2018-01-19 22:45:04 +01:00
gl - > hw_render_use = false ;
gl - > has_fbo = gl_check_capability ( GL_CAPS_FBO ) ;
2018-10-09 20:42:47 +02:00
if ( gl - > has_fbo & & hwr - > context_type ! = RETRO_HW_CONTEXT_NONE )
2018-01-19 22:45:04 +01:00
gl - > hw_render_use = true ;
2019-02-06 19:49:45 +01:00
if ( ! gl2_resolve_extensions ( gl , ctx_driver - > ident , video ) )
2015-04-10 06:17:04 +02:00
goto error ;
2011-01-11 22:33:28 +01:00
2013-08-14 14:00:21 +02:00
# ifdef GL_DEBUG
2019-02-06 19:43:31 +01:00
gl2_begin_debug ( gl ) ;
2013-08-14 14:00:21 +02:00
# endif
2017-04-24 12:25:14 +02:00
gl - > vsync = video - > vsync ;
gl - > fullscreen = video - > fullscreen ;
2016-02-14 02:26:20 +01:00
2020-07-27 14:33:21 +02:00
mode_width = 0 ;
mode_height = 0 ;
2016-02-14 02:26:20 +01:00
2020-07-27 14:33:21 +02:00
if ( gl - > ctx_driver - > get_video_size )
gl - > ctx_driver - > get_video_size ( gl - > ctx_data ,
& mode_width , & mode_height ) ;
2016-02-14 02:26:20 +01:00
2019-12-28 21:21:57 -05:00
# if defined(DINGUX)
2020-07-27 14:33:21 +02:00
mode_width = 320 ;
mode_height = 240 ;
2019-12-28 21:21:57 -05:00
# endif
2020-07-27 14:33:21 +02:00
temp_width = mode_width ;
temp_height = mode_height ;
2016-09-17 20:57:17 -03:00
2017-04-24 12:25:14 +02:00
/* Get real known video size, which might have been altered by context. */
2015-05-20 02:18:05 +02:00
2017-04-24 12:25:14 +02:00
if ( temp_width ! = 0 & & temp_height ! = 0 )
2020-01-31 03:47:50 +01:00
video_driver_set_size ( temp_width , temp_height ) ;
2017-04-24 12:25:14 +02:00
video_driver_get_size ( & temp_width , & temp_height ) ;
2019-08-13 12:14:33 +02:00
gl - > video_width = temp_width ;
gl - > video_height = temp_height ;
2017-04-24 12:25:14 +02:00
2021-12-04 15:21:12 +02:00
RARCH_LOG ( " [GL]: Using resolution %ux%u. \n " , temp_width , temp_height ) ;
2017-04-24 12:25:14 +02:00
2018-10-09 20:42:47 +02:00
gl - > vertex_ptr = hwr - > bottom_left_origin
2016-02-14 16:59:21 +01:00
? vertexes : vertexes_flipped ;
2013-06-30 22:58:22 +02:00
2014-10-01 23:50:58 +02:00
/* Better pipelining with GPU due to synchronous glSubTexImage.
* Multiple async PBOs would be an alternative ,
* but still need multiple textures with PREV .
*/
2017-11-08 16:00:37 +01:00
gl - > textures = 4 ;
2015-01-10 03:48:03 +01:00
2013-07-06 22:10:09 +02:00
if ( gl - > hw_render_use )
2014-04-19 15:37:00 +02:00
{
2014-10-01 23:50:58 +02:00
/* All on GPU, no need to excessively
* create textures . */
2017-04-24 12:25:14 +02:00
gl - > textures = 1 ;
2014-04-19 15:37:00 +02:00
# ifdef GL_DEBUG
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
gl2_begin_debug ( gl ) ;
gl2_context_bind_hw_render ( gl , false ) ;
2014-04-19 15:37:00 +02:00
# endif
}
2017-11-07 21:34:25 +01:00
2013-06-30 22:58:22 +02:00
gl - > white_color_ptr = white_color ;
2019-02-06 19:43:31 +01:00
gl - > shader = ( shader_backend_t * ) gl2_shader_ctx_drivers [ 0 ] ;
2019-02-05 01:13:39 +01:00
2019-03-18 15:52:21 +01:00
if ( ! gl - > shader )
2016-10-31 15:12:34 +01:00
{
RARCH_ERR ( " [GL:]: Shader driver initialization failed. \n " ) ;
2015-12-08 09:27:25 +01:00
goto error ;
2016-10-31 15:12:34 +01:00
}
2014-10-02 13:47:45 +02:00
2019-03-18 15:57:43 +01:00
RARCH_LOG ( " [GL]: Default shader backend found: %s. \n " , gl - > shader - > ident ) ;
2014-10-02 13:47:45 +02:00
2019-02-06 19:43:31 +01:00
if ( ! gl2_shader_init ( gl , ctx_driver , hwr ) )
2011-01-11 19:23:21 +01:00
{
2014-12-03 18:36:25 +01:00
RARCH_ERR ( " [GL]: Shader initialization failed. \n " ) ;
2015-04-10 06:17:04 +02:00
goto error ;
2011-01-11 19:23:21 +01:00
}
2013-07-06 22:10:09 +02:00
{
2019-02-03 05:49:18 +01:00
unsigned texture_info_id = gl - > shader - > get_prev_textures ( gl - > shader_data ) ;
unsigned minimum = texture_info_id ;
gl - > textures = MAX ( minimum + 1 , gl - > textures ) ;
2013-07-06 22:10:09 +02:00
}
2019-02-06 19:43:31 +01:00
if ( ! gl2_shader_info ( gl , & shader_info ) )
2019-02-03 19:40:27 +01:00
{
RARCH_ERR ( " [GL]: Shader driver info check failed. \n " ) ;
goto error ;
}
2016-02-14 19:30:48 +01:00
2014-10-02 13:47:45 +02:00
RARCH_LOG ( " [GL]: Using %u textures. \n " , gl - > textures ) ;
2016-02-14 16:59:21 +01:00
RARCH_LOG ( " [GL]: Loaded %u program(s). \n " ,
2016-02-14 19:30:48 +01:00
shader_info . num ) ;
2011-03-12 15:30:57 +01:00
2015-02-13 02:21:54 +01:00
gl - > tex_w = gl - > tex_h = ( RARCH_SCALE_BASE * video - > input_scale ) ;
2017-04-24 12:25:14 +02:00
gl - > keep_aspect = video - > force_aspect ;
2011-03-30 14:57:45 +02:00
2020-03-04 23:36:22 -05:00
# if defined(HAVE_ODROIDGO2)
if ( settings - > bools . video_ctx_scaling )
gl - > keep_aspect = false ;
else
# endif
2016-09-17 20:57:17 -03:00
/* Apparently need to set viewport for passes
2014-10-01 23:50:58 +02:00
* when we aren ' t using FBOs . */
2019-02-06 19:43:31 +01:00
gl2_set_shader_viewports ( gl ) ;
2011-01-06 20:01:32 +01:00
2017-04-24 12:25:14 +02:00
mip_level = 1 ;
2019-02-03 04:47:52 +01:00
gl - > tex_mipmap = gl - > shader - > mipmap_input ( gl - > shader_data , mip_level ) ;
2016-02-14 19:51:32 +01:00
2019-02-03 05:28:00 +01:00
if ( gl - > shader - > filter_type ( gl - > shader_data ,
2019-02-03 05:32:03 +01:00
1 , & force_smooth ) )
2016-09-17 20:57:17 -03:00
gl - > tex_min_filter = gl - > tex_mipmap ? ( force_smooth ?
GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST )
2014-10-01 23:50:58 +02:00
: ( force_smooth ? GL_LINEAR : GL_NEAREST ) ;
2010-05-29 14:45:40 +02:00
else
2016-09-17 20:57:17 -03:00
gl - > tex_min_filter = gl - > tex_mipmap ?
( video - > smooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST )
2014-10-01 23:50:58 +02:00
: ( video - > smooth ? GL_LINEAR : GL_NEAREST ) ;
2016-09-17 20:57:17 -03:00
2019-02-06 19:43:31 +01:00
gl - > tex_mag_filter = gl2_min_filter_to_mag ( gl - > tex_min_filter ) ;
2016-02-14 21:41:16 +01:00
2019-02-03 05:41:43 +01:00
wrap_type = gl - > shader - > wrap_type (
gl - > shader_data , 1 ) ;
2016-02-14 21:41:16 +01:00
2019-02-06 19:43:31 +01:00
gl - > wrap_mode = gl2_wrap_type_to_enum ( wrap_type ) ;
2010-05-28 02:54:20 +02:00
2019-02-06 19:43:31 +01:00
gl2_set_texture_fmts ( gl , video - > rgb32 ) ;
2011-03-07 19:12:14 +01:00
2014-10-01 20:37:52 +02:00
memcpy ( gl - > tex_info . coord , tex_coords , sizeof ( gl - > tex_info . coord ) ) ;
2013-06-30 22:24:07 +02:00
gl - > coords . vertex = gl - > vertex_ptr ;
2014-10-01 20:37:52 +02:00
gl - > coords . tex_coord = gl - > tex_info . coord ;
2013-06-30 22:24:07 +02:00
gl - > coords . color = gl - > white_color_ptr ;
2012-09-11 23:32:00 +02:00
gl - > coords . lut_tex_coord = tex_coords ;
2014-06-07 21:18:58 +02:00
gl - > coords . vertices = 4 ;
2011-05-18 20:38:04 +02:00
2016-09-17 20:57:17 -03:00
/* Empty buffer that we use to clear out
2014-10-01 23:50:58 +02:00
* the texture with on res change . */
2015-02-13 02:21:54 +01:00
gl - > empty_buf = calloc ( sizeof ( uint32_t ) , gl - > tex_w * gl - > tex_h ) ;
2012-09-15 15:17:34 +02:00
2015-02-13 02:21:54 +01:00
gl - > conv_buffer = calloc ( sizeof ( uint32_t ) , gl - > tex_w * gl - > tex_h ) ;
2015-01-11 19:52:02 +01:00
2012-09-15 15:17:34 +02:00
if ( ! gl - > conv_buffer )
2015-04-10 06:17:04 +02:00
goto error ;
2012-09-15 15:17:34 +02:00
2020-03-07 00:58:06 +01:00
gl2_init_textures ( gl ) ;
2019-02-06 19:43:31 +01:00
gl2_init_textures_data ( gl ) ;
2010-05-28 02:45:18 +02:00
2019-02-07 23:16:25 +01:00
gl2_renderchain_init ( gl ,
( gl2_renderchain_data_t * ) gl - > renderchain_data ,
gl - > tex_w , gl - > tex_h ) ;
2013-03-27 16:15:15 +01:00
2017-11-13 05:23:15 +01:00
if ( gl - > has_fbo )
2016-10-31 15:12:34 +01:00
{
2017-11-12 17:15:29 +01:00
if ( gl - > hw_render_use & &
2019-02-07 23:16:25 +01:00
! gl2_renderchain_init_hw_render ( gl , ( gl2_renderchain_data_t * ) gl - > renderchain_data , gl - > tex_w , gl - > tex_h ) )
2017-11-12 17:15:29 +01:00
{
RARCH_ERR ( " [GL]: Hardware rendering context initialization failed. \n " ) ;
goto error ;
}
2016-10-31 15:12:34 +01:00
}
2013-03-27 16:15:15 +01:00
2020-08-03 00:47:58 +02:00
if ( gl - > ctx_driver - > input_driver )
{
const char * joypad_name = settings - > arrays . input_joypad_driver ;
gl - > ctx_driver - > input_driver (
gl - > ctx_data , joypad_name ,
input , input_data ) ;
}
2016-09-17 20:57:17 -03:00
2017-01-10 18:08:05 +01:00
if ( video - > font_enable )
2020-02-16 21:59:03 +01:00
font_driver_init_osd ( gl , video ,
false ,
2017-04-29 16:52:52 +02:00
video - > is_threaded ,
FONT_DRIVER_RENDER_OPENGL_API ) ;
2012-09-10 23:17:48 +02:00
2017-11-08 16:49:42 +01:00
/* Only bother with PBO readback if we're doing GPU recording.
2021-11-10 02:34:04 +01:00
* Check recording_st - > enable and not
2017-11-08 16:49:42 +01:00
* driver . recording_data , because recording is
* not initialized yet .
*/
2020-03-02 20:24:00 +01:00
gl - > pbo_readback_enable = video_gpu_record
2021-11-10 02:34:04 +01:00
& & recording_st - > enable ;
2017-11-08 16:49:42 +01:00
2019-02-06 19:43:31 +01:00
if ( gl - > pbo_readback_enable & & gl2_init_pbo_readback ( gl ) )
2017-11-08 16:49:42 +01:00
{
RARCH_LOG ( " [GL]: Async PBO readback enabled. \n " ) ;
}
2012-11-21 16:24:28 +01:00
2016-09-17 20:55:19 -03:00
if ( ! gl_check_error ( & error_string ) )
2016-09-05 07:21:47 +02:00
{
2021-02-18 18:33:47 +02:00
RARCH_ERR ( " [GL]: %s \n " , error_string ) ;
2016-09-05 07:21:47 +02:00
free ( error_string ) ;
2015-04-10 06:17:04 +02:00
goto error ;
2016-09-05 07:21:47 +02:00
}
2011-01-11 22:33:28 +01:00
2019-04-03 05:04:17 +01:00
# ifdef HAVE_VIDEO_LAYOUT
gl2_video_layout_init ( gl ) ;
# endif
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2018-11-22 15:45:52 +01:00
2010-08-16 18:40:17 +02:00
return gl ;
2015-04-10 06:17:04 +02:00
error :
2021-09-28 01:16:53 +02:00
video_context_driver_free ( ) ;
2019-02-06 19:43:31 +01:00
gl2_destroy_resources ( gl ) ;
2015-04-10 06:17:04 +02:00
return NULL ;
2010-05-28 02:45:18 +02:00
}
2019-02-06 19:43:31 +01:00
static bool gl2_alive ( void * data )
2011-01-06 20:01:32 +01:00
{
2016-02-13 19:53:14 +01:00
bool ret = false ;
bool quit = false ;
bool resize = false ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2019-08-13 12:14:33 +02:00
unsigned temp_width = gl - > video_width ;
unsigned temp_height = gl - > video_height ;
2015-12-01 07:15:06 +01:00
2018-10-14 08:40:00 +02:00
gl - > ctx_driver - > check_window ( gl - > ctx_data ,
2020-03-06 20:29:15 +01:00
& quit , & resize , & temp_width , & temp_height ) ;
2016-02-13 19:53:14 +01:00
2021-12-24 13:34:30 +00:00
# ifdef __WINRT__
if ( is_running_on_xbox ( ) )
{
//we can set it to 1920x1080 as xbox uwp windowsize is guaranteed to be 1920x1080 and currently there is now way to set angle to use a variable resolution swapchain so regardless of the size the window is always 1080p
temp_width = 1920 ;
temp_height = 1080 ;
}
# endif
2018-10-14 08:40:00 +02:00
if ( quit )
gl - > quitting = true ;
else if ( resize )
gl - > should_resize = true ;
2015-04-09 22:38:11 +02:00
2018-10-14 08:40:00 +02:00
ret = ! gl - > quitting ;
2012-05-30 17:02:38 +02:00
2015-05-20 02:22:03 +02:00
if ( temp_width ! = 0 & & temp_height ! = 0 )
2019-08-13 12:14:33 +02:00
{
2020-01-31 03:47:50 +01:00
video_driver_set_size ( temp_width , temp_height ) ;
2019-08-13 12:14:33 +02:00
gl - > video_width = temp_width ;
gl - > video_height = temp_height ;
}
2015-05-20 02:22:03 +02:00
return ret ;
2011-01-06 20:01:32 +01:00
}
2019-02-06 19:43:31 +01:00
static bool gl2_suppress_screensaver ( void * data , bool enable )
2015-01-18 22:32:14 +01:00
{
2016-02-13 23:39:12 +01:00
bool enabled = enable ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2019-08-28 22:52:41 +02:00
if ( gl - > ctx_data & & gl - > ctx_driver - > suppress_screensaver )
return gl - > ctx_driver - > suppress_screensaver ( gl - > ctx_data , enabled ) ;
return false ;
2015-01-18 22:32:14 +01:00
}
2021-09-26 17:42:12 +02:00
static void gl2_update_tex_filter_frame ( gl2_t * gl )
2013-04-14 01:56:13 +02:00
{
2016-02-14 18:48:17 +01:00
unsigned i , mip_level ;
2015-01-10 03:48:03 +01:00
GLenum wrap_mode ;
GLuint new_filt ;
2019-02-03 05:41:43 +01:00
enum gfx_wrap_type wrap_type ;
2016-05-09 04:54:25 +02:00
bool smooth = false ;
settings_t * settings = config_get_ptr ( ) ;
2020-02-18 14:51:40 +01:00
bool video_smooth = settings - > bools . video_smooth ;
2020-03-04 23:36:22 -05:00
# ifdef HAVE_ODROIDGO2
2020-04-01 20:43:03 +02:00
bool video_ctx_scaling = settings - > bools . video_ctx_scaling ;
2020-03-04 23:36:22 -05:00
if ( video_ctx_scaling )
video_smooth = false ;
# endif
2014-05-29 00:43:47 +02:00
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2015-02-13 02:21:54 +01:00
2019-02-03 05:28:00 +01:00
if ( ! gl - > shader - > filter_type ( gl - > shader_data ,
2019-02-03 05:32:03 +01:00
1 , & smooth ) )
2020-02-18 14:51:40 +01:00
smooth = video_smooth ;
2013-04-14 01:56:13 +02:00
2019-02-03 05:41:43 +01:00
mip_level = 1 ;
2019-06-04 21:52:58 +02:00
wrap_type = gl - > shader - > wrap_type ( gl - > shader_data , 1 ) ;
2019-02-06 19:43:31 +01:00
wrap_mode = gl2_wrap_type_to_enum ( wrap_type ) ;
2019-02-03 04:47:52 +01:00
gl - > tex_mipmap = gl - > shader - > mipmap_input ( gl - > shader_data , mip_level ) ;
2013-07-06 22:10:09 +02:00
gl - > video_info . smooth = smooth ;
2017-03-25 10:13:18 +01:00
new_filt = gl - > tex_mipmap ? ( smooth ?
2016-09-17 20:57:17 -03:00
GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST )
2014-10-01 23:50:58 +02:00
: ( smooth ? GL_LINEAR : GL_NEAREST ) ;
2015-02-13 02:21:54 +01:00
2014-05-11 13:13:38 +02:00
if ( new_filt = = gl - > tex_min_filter & & wrap_mode = = gl - > wrap_mode )
2013-04-14 01:56:13 +02:00
return ;
2015-02-13 02:21:54 +01:00
gl - > tex_min_filter = new_filt ;
2019-02-06 19:43:31 +01:00
gl - > tex_mag_filter = gl2_min_filter_to_mag ( gl - > tex_min_filter ) ;
2015-02-13 02:21:54 +01:00
gl - > wrap_mode = wrap_mode ;
2014-05-11 13:13:38 +02:00
2013-10-22 15:08:17 +02:00
for ( i = 0 ; i < gl - > textures ; i + + )
2013-04-14 01:56:13 +02:00
{
2015-01-11 19:52:02 +01:00
if ( ! gl - > texture [ i ] )
continue ;
2021-09-26 17:42:12 +02:00
GL2_BIND_TEXTURE ( gl - > texture [ i ] , gl - > wrap_mode , gl - > tex_mag_filter ,
2017-11-10 03:55:10 +01:00
gl - > tex_min_filter ) ;
2013-04-14 01:56:13 +02:00
}
glBindTexture ( GL_TEXTURE_2D , gl - > texture [ gl - > tex_index ] ) ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2013-04-14 01:56:13 +02:00
}
2019-02-06 19:43:31 +01:00
static bool gl2_set_shader ( void * data ,
2014-10-01 23:50:58 +02:00
enum rarch_shader_type type , const char * path )
2011-03-29 18:28:31 +02:00
{
2014-09-09 06:07:11 +02:00
# if defined(HAVE_GLSL) || defined(HAVE_CG)
2016-04-16 07:16:32 +02:00
unsigned textures ;
2016-02-14 18:41:45 +01:00
video_shader_ctx_init_t init_data ;
2019-06-04 21:52:58 +02:00
enum rarch_shader_type fallback ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2014-05-29 00:43:47 +02:00
if ( ! gl )
return false ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2011-06-07 15:58:30 +02:00
2019-06-04 21:52:58 +02:00
fallback = gl2_get_fallback_shader_type ( type ) ;
2012-09-21 21:20:30 +02:00
2019-06-04 21:52:58 +02:00
if ( fallback = = RARCH_SHADER_NONE )
{
RARCH_ERR ( " [GL]: No supported shader backend found! \n " ) ;
goto error ;
}
2019-06-21 13:43:56 +02:00
gl - > shader - > deinit ( gl - > shader_data ) ;
gl - > shader_data = NULL ;
2019-06-04 21:52:58 +02:00
if ( type ! = fallback )
{
RARCH_ERR ( " [GL]: %s shader not supported, falling back to stock %s \n " ,
2020-12-26 21:09:27 -05:00
video_shader_type_to_str ( type ) , video_shader_type_to_str ( fallback ) ) ;
2019-06-04 21:52:58 +02:00
path = NULL ;
2013-04-07 13:00:21 +02:00
}
2013-01-08 03:46:18 +01:00
2017-11-12 17:15:29 +01:00
if ( gl - > fbo_inited )
{
2019-02-07 23:16:25 +01:00
gl2_renderchain_deinit_fbo ( gl ,
( gl2_renderchain_data_t * ) gl - > renderchain_data ) ;
2017-11-12 17:15:29 +01:00
glBindTexture ( GL_TEXTURE_2D , gl - > texture [ gl - > tex_index ] ) ;
}
2013-01-08 03:46:18 +01:00
2020-06-29 19:40:17 +02:00
init_data . shader_type = fallback ;
init_data . path = path ;
init_data . shader = NULL ;
init_data . data = gl ;
init_data . shader_data = NULL ;
init_data . gl . core_context_enabled = false ;
2016-02-14 18:41:45 +01:00
2019-03-18 15:52:21 +01:00
if ( ! gl_shader_driver_init ( & init_data ) )
2013-04-07 13:00:21 +02:00
{
2020-06-29 19:40:17 +02:00
init_data . path = NULL ;
2016-02-14 18:41:45 +01:00
2019-03-18 15:52:21 +01:00
gl_shader_driver_init ( & init_data ) ;
2015-02-13 02:21:54 +01:00
2019-02-03 04:37:54 +01:00
gl - > shader = init_data . shader ;
gl - > shader_data = init_data . shader_data ;
2013-04-07 13:00:21 +02:00
RARCH_WARN ( " [GL]: Failed to set multipass shader. Falling back to stock. \n " ) ;
2015-02-13 02:21:54 +01:00
2016-04-16 07:19:21 +02:00
goto error ;
2013-04-07 13:00:21 +02:00
}
2011-03-29 18:59:06 +02:00
2019-02-03 04:37:54 +01:00
gl - > shader = init_data . shader ;
gl - > shader_data = init_data . shader_data ;
2019-02-06 19:43:31 +01:00
gl2_update_tex_filter_frame ( gl ) ;
2013-04-14 01:31:32 +02:00
2019-02-03 05:49:18 +01:00
{
unsigned texture_info_id = gl - > shader - > get_prev_textures ( gl - > shader_data ) ;
2019-02-06 19:49:45 +01:00
textures = texture_info_id + 1 ;
2019-02-03 05:49:18 +01:00
}
2016-02-14 22:22:40 +01:00
2016-04-16 07:16:32 +02:00
if ( textures > gl - > textures ) /* Have to reinit a bit. */
{
2019-02-03 00:07:53 +01:00
if ( gl - > hw_render_use & & gl - > fbo_inited )
2019-02-07 23:16:25 +01:00
gl2_renderchain_deinit_hw_render ( gl , ( gl2_renderchain_data_t * )
gl - > renderchain_data ) ;
2013-07-06 22:10:09 +02:00
2016-04-16 07:16:32 +02:00
glDeleteTextures ( gl - > textures , gl - > texture ) ;
2013-07-06 22:10:09 +02:00
# if defined(HAVE_PSGL)
2016-04-16 07:16:32 +02:00
glBindBuffer ( GL_TEXTURE_REFERENCE_BUFFER_SCE , 0 ) ;
glDeleteBuffers ( 1 , & gl - > pbo ) ;
2013-07-06 22:10:09 +02:00
# endif
2020-03-07 00:58:06 +01:00
gl - > textures = textures ;
2016-04-16 07:16:32 +02:00
gl - > tex_index = 0 ;
2020-03-07 00:58:06 +01:00
RARCH_LOG ( " [GL]: Using %u textures. \n " , gl - > textures ) ;
gl2_init_textures ( gl ) ;
2019-02-06 19:43:31 +01:00
gl2_init_textures_data ( gl ) ;
2013-07-06 22:10:09 +02:00
2019-02-03 00:07:53 +01:00
if ( gl - > hw_render_use )
2019-04-03 05:04:17 +01:00
gl2_renderchain_init_hw_render ( gl ,
2019-02-07 23:16:25 +01:00
( gl2_renderchain_data_t * ) gl - > renderchain_data ,
2017-12-04 11:54:30 +01:00
gl - > tex_w , gl - > tex_h ) ;
2013-07-06 22:10:09 +02:00
}
2019-02-07 23:16:25 +01:00
gl2_renderchain_init ( gl ,
( gl2_renderchain_data_t * ) gl - > renderchain_data ,
2019-02-03 00:07:53 +01:00
gl - > tex_w , gl - > tex_h ) ;
2011-03-29 18:59:06 +02:00
2014-10-01 16:59:43 +02:00
/* Apparently need to set viewport for passes when we aren't using FBOs. */
2019-02-06 19:43:31 +01:00
gl2_set_shader_viewports ( gl ) ;
gl2_context_bind_hw_render ( gl , true ) ;
2016-04-16 07:19:21 +02:00
2013-04-07 13:00:21 +02:00
return true ;
2016-04-16 07:19:21 +02:00
error :
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2019-06-04 21:52:58 +02:00
# endif
2014-09-09 06:07:11 +02:00
return false ;
}
2011-03-29 18:28:31 +02:00
2019-02-06 19:43:31 +01:00
static void gl2_viewport_info ( void * data , struct video_viewport * vp )
2012-06-08 22:39:18 +02:00
{
2018-05-13 05:56:44 +02:00
unsigned top_y , top_dist ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2019-08-13 12:14:33 +02:00
unsigned width = gl - > video_width ;
unsigned height = gl - > video_height ;
2018-05-13 05:56:44 +02:00
* 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 ;
2012-06-08 22:39:18 +02:00
}
2019-02-06 19:43:31 +01:00
static bool gl2_read_viewport ( void * data , uint8_t * buffer , bool is_idle )
2015-01-10 03:48:03 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2019-06-04 21:52:58 +02:00
2019-02-03 00:07:53 +01:00
if ( ! gl )
2017-11-07 20:56:08 +01:00
return false ;
2019-06-04 21:52:58 +02:00
return gl2_renderchain_read_viewport ( gl , buffer , is_idle ) ;
2014-09-09 06:07:11 +02:00
}
2012-06-08 22:39:18 +02:00
2015-03-16 13:39:25 +01:00
#if 0
# define READ_RAW_GL_FRAME_TEST
# endif
# if defined(READ_RAW_GL_FRAME_TEST)
2019-02-06 19:43:31 +01:00
static void * gl2_read_frame_raw ( void * data , unsigned * width_p ,
2015-03-16 13:39:25 +01:00
unsigned * height_p , size_t * pitch_p )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2015-09-28 18:44:28 +02:00
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 ;
2016-08-06 03:18:19 +02:00
void * buffer = NULL ;
2015-03-16 16:28:30 +01:00
void * buffer_texture = NULL ;
2015-03-16 15:29:52 +01:00
if ( gl - > hw_render_use )
2015-03-16 16:22:48 +01:00
{
2015-03-16 15:29:52 +01:00
buffer = malloc ( pitch * height ) ;
2015-03-16 16:22:48 +01:00
if ( ! buffer )
return NULL ;
}
2016-08-06 03:18:19 +02:00
2015-03-16 15:29:52 +01:00
buffer_texture = malloc ( pitch * gl - > tex_h ) ;
2015-03-16 13:39:25 +01:00
2015-03-16 16:22:48 +01:00
if ( ! buffer_texture )
{
if ( buffer )
free ( buffer ) ;
return NULL ;
}
2015-03-16 13:39:25 +01:00
glBindTexture ( GL_TEXTURE_2D , gl - > texture [ gl - > tex_index ] ) ;
2016-02-14 16:59:21 +01:00
glGetTexImage ( GL_TEXTURE_2D , 0 ,
gl - > texture_type , gl - > texture_fmt , buffer_texture ) ;
2015-03-16 13:39:25 +01:00
2016-08-06 03:18:19 +02:00
* width_p = width ;
2015-03-16 13:39:25 +01:00
* height_p = height ;
2016-08-06 03:18:19 +02:00
* pitch_p = pitch ;
2015-03-16 13:39:25 +01:00
2015-03-16 15:29:52 +01:00
if ( gl - > hw_render_use )
{
2015-09-28 18:44:28 +02:00
unsigned i ;
2020-08-19 03:06:22 +02:00
for ( i = 0 ; i < height ; i + + )
2015-03-16 15:29:52 +01:00
memcpy ( ( uint8_t * ) buffer + i * pitch ,
( uint8_t * ) buffer_texture + ( height - 1 - i ) * pitch , pitch ) ;
2015-03-16 13:39:25 +01:00
2015-03-16 15:29:52 +01:00
free ( buffer_texture ) ;
return buffer ;
}
2017-11-07 21:34:25 +01:00
2015-03-16 15:29:52 +01:00
return buffer_texture ;
2015-03-16 13:39:25 +01:00
}
# endif
2012-12-23 18:36:58 +01:00
# ifdef HAVE_OVERLAY
2019-02-06 19:43:31 +01:00
static bool gl2_overlay_load ( void * data ,
2015-07-11 08:14:39 +02:00
const void * image_data , unsigned num_images )
2012-12-19 13:26:11 +01:00
{
2014-06-13 17:46:53 +02:00
unsigned i , j ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-09-17 20:57:17 -03:00
const struct texture_image * images =
2015-07-11 08:14:39 +02:00
( const struct texture_image * ) image_data ;
2015-01-10 03:48:03 +01:00
2014-05-29 00:43:47 +02:00
if ( ! gl )
return false ;
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , false ) ;
2012-12-20 11:16:22 +01:00
2019-02-06 19:43:31 +01:00
gl2_free_overlay ( gl ) ;
2017-11-08 00:07:04 +01:00
gl - > overlay_tex = ( GLuint * )
calloc ( num_images , sizeof ( * gl - > overlay_tex ) ) ;
2015-02-13 02:21:54 +01:00
2014-06-13 17:46:53 +02:00
if ( ! gl - > overlay_tex )
2014-04-19 15:37:00 +02:00
{
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2013-10-15 16:06:59 +02:00
return false ;
2014-04-19 15:37:00 +02:00
}
2013-10-15 16:06:59 +02:00
2016-02-14 16:59:21 +01:00
gl - > overlay_vertex_coord = ( GLfloat * )
calloc ( 2 * 4 * num_images , sizeof ( GLfloat ) ) ;
gl - > overlay_tex_coord = ( GLfloat * )
calloc ( 2 * 4 * num_images , sizeof ( GLfloat ) ) ;
gl - > overlay_color_coord = ( GLfloat * )
calloc ( 4 * 4 * num_images , sizeof ( GLfloat ) ) ;
2015-02-13 02:21:54 +01:00
2016-09-17 20:57:17 -03:00
if ( ! gl - > overlay_vertex_coord
| | ! gl - > overlay_tex_coord
2016-02-14 16:59:21 +01:00
| | ! gl - > overlay_color_coord )
2014-06-13 17:46:53 +02:00
return false ;
2019-06-04 21:52:58 +02:00
gl - > overlays = num_images ;
2014-06-13 17:46:53 +02:00
glGenTextures ( num_images , gl - > overlay_tex ) ;
2012-12-19 13:26:11 +01:00
2013-10-22 15:08:17 +02:00
for ( i = 0 ; i < num_images ; i + + )
2013-10-15 16:06:59 +02:00
{
2021-03-11 02:03:37 +01:00
unsigned alignment = gl2_get_alignment ( images [ i ] . width
2015-02-11 15:46:55 +01:00
* sizeof ( uint32_t ) ) ;
2014-10-01 23:50:58 +02:00
2015-02-11 15:46:55 +01:00
gl_load_texture_data ( gl - > overlay_tex [ i ] ,
RARCH_WRAP_EDGE , TEXTURE_FILTER_LINEAR ,
2015-02-11 15:53:37 +01:00
alignment ,
2015-02-11 16:05:11 +01:00
images [ i ] . width , images [ i ] . height , images [ i ] . pixels ,
sizeof ( uint32_t ) ) ;
2012-12-19 13:26:11 +01:00
2014-10-01 23:50:58 +02:00
/* Default. Stretch to whole screen. */
2019-02-06 19:43:31 +01:00
gl2_overlay_tex_geom ( gl , i , 0 , 0 , 1 , 1 ) ;
gl2_overlay_vertex_geom ( gl , i , 0 , 0 , 1 , 1 ) ;
2015-01-10 03:48:03 +01:00
2014-06-13 17:46:53 +02:00
for ( j = 0 ; j < 16 ; j + + )
gl - > overlay_color_coord [ 16 * i + j ] = 1.0f ;
2013-10-15 16:06:59 +02:00
}
2013-01-29 21:51:15 +01:00
2019-02-06 19:43:31 +01:00
gl2_context_bind_hw_render ( gl , true ) ;
2012-12-19 13:26:11 +01:00
return true ;
}
2019-02-06 19:43:31 +01:00
static void gl2_overlay_enable ( void * data , bool state )
2012-12-20 11:16:22 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2014-05-29 00:43:47 +02:00
2014-10-01 16:59:43 +02:00
if ( ! gl )
return ;
gl - > overlay_enable = state ;
2015-04-10 08:49:01 +02:00
2019-08-28 21:36:58 +02:00
if ( gl - > fullscreen & & gl - > ctx_driver - > show_mouse )
gl - > ctx_driver - > show_mouse ( gl - > ctx_data , state ) ;
2012-12-20 11:16:22 +01:00
}
2019-02-06 19:43:31 +01:00
static void gl2_overlay_full_screen ( void * data , bool enable )
2013-01-11 16:23:04 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2014-05-29 00:43:47 +02:00
if ( gl )
gl - > overlay_full_screen = enable ;
2013-01-11 16:23:04 +01:00
}
2019-02-06 19:43:31 +01:00
static void gl2_overlay_set_alpha ( void * data , unsigned image , float mod )
2013-01-29 21:51:15 +01:00
{
2019-06-04 21:52:58 +02:00
GLfloat * color ;
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2019-06-04 21:52:58 +02:00
2014-06-13 17:46:53 +02:00
if ( ! gl )
return ;
2014-05-29 00:43:47 +02:00
2019-06-04 21:52:58 +02:00
color = ( GLfloat * ) & gl - > overlay_color_coord [ image * 16 ] ;
2014-10-01 16:59:43 +02:00
2019-06-04 21:52:58 +02:00
color [ 0 + 3 ] = mod ;
color [ 4 + 3 ] = mod ;
color [ 8 + 3 ] = mod ;
color [ 12 + 3 ] = mod ;
2013-01-29 21:51:15 +01:00
}
2019-02-06 19:43:31 +01:00
static const video_overlay_interface_t gl2_overlay_interface = {
gl2_overlay_enable ,
gl2_overlay_load ,
gl2_overlay_tex_geom ,
gl2_overlay_vertex_geom ,
gl2_overlay_full_screen ,
gl2_overlay_set_alpha ,
2012-12-20 11:16:22 +01:00
} ;
2019-02-06 19:43:31 +01:00
static void gl2_get_overlay_interface ( void * data ,
2014-10-01 23:50:58 +02:00
const video_overlay_interface_t * * iface )
2012-12-20 11:16:22 +01:00
{
( void ) data ;
2019-02-06 19:43:31 +01:00
* iface = & gl2_overlay_interface ;
2012-12-20 11:16:22 +01:00
}
2012-12-23 18:36:58 +01:00
# endif
2012-12-20 11:16:22 +01:00
2019-02-06 19:43:31 +01:00
static retro_proc_address_t gl2_get_proc_address ( void * data , const char * sym )
2013-03-28 01:11:32 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-02-13 22:02:49 +01:00
2019-08-28 21:26:43 +02:00
if ( gl & & gl - > ctx_driver - > get_proc_address )
return gl - > ctx_driver - > get_proc_address ( sym ) ;
2016-02-13 22:02:49 +01:00
2019-08-28 21:26:43 +02:00
return NULL ;
2013-03-28 01:11:32 +01:00
}
2013-03-10 20:12:50 +01:00
2019-02-06 19:43:31 +01:00
static void gl2_set_aspect_ratio ( void * data , unsigned aspect_ratio_idx )
2013-03-10 01:16:56 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2013-03-10 01:16:56 +01:00
2014-10-01 16:59:43 +02:00
if ( ! gl )
return ;
2019-08-12 12:52:40 +02:00
gl - > keep_aspect = true ;
2020-03-04 23:36:22 -05:00
# if defined(HAVE_ODROIDGO2)
if ( config_get_ptr ( ) - > bools . video_ctx_scaling )
gl - > keep_aspect = false ;
# endif
2014-10-01 16:59:43 +02:00
gl - > should_resize = true ;
2013-03-10 01:16:56 +01:00
}
2019-02-06 19:43:31 +01:00
static void gl2_apply_state_changes ( void * data )
2016-08-01 15:31:17 +02:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2016-08-01 15:31:17 +02:00
if ( gl )
gl - > should_resize = true ;
}
2019-02-06 19:43:31 +01:00
static void gl2_get_video_output_size ( void * data ,
2021-09-07 20:25:22 +02:00
unsigned * width , unsigned * height , char * desc , size_t desc_len )
2015-02-24 20:09:10 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-07-27 09:38:20 +02:00
if ( ! gl | | ! gl - > ctx_driver | | ! gl - > ctx_driver - > get_video_output_size )
return ;
gl - > ctx_driver - > get_video_output_size (
gl - > ctx_data ,
2021-09-07 20:25:22 +02:00
width , height , desc , desc_len ) ;
2015-02-24 20:09:10 +01:00
}
2019-02-06 19:43:31 +01:00
static void gl2_get_video_output_prev ( void * data )
2015-02-24 21:36:23 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-07-27 09:38:20 +02:00
if ( ! gl | | ! gl - > ctx_driver | | ! gl - > ctx_driver - > get_video_output_prev )
return ;
gl - > ctx_driver - > get_video_output_prev ( gl - > ctx_data ) ;
2015-02-24 21:36:23 +01:00
}
2019-02-06 19:43:31 +01:00
static void gl2_get_video_output_next ( void * data )
2015-02-24 21:36:23 +01:00
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-07-27 09:38:20 +02:00
if ( ! gl | | ! gl - > ctx_driver | | ! gl - > ctx_driver - > get_video_output_next )
return ;
gl - > ctx_driver - > get_video_output_next ( gl - > ctx_data ) ;
2015-02-24 21:36:23 +01:00
}
2019-02-06 19:49:45 +01:00
static void video_texture_load_gl2 (
2015-12-20 20:52:23 +01:00
struct texture_image * ti ,
enum texture_filter_type filter_type ,
2020-02-18 04:18:31 +01:00
uintptr_t * idptr )
2015-12-20 20:52:23 +01:00
{
2020-02-18 04:18:31 +01:00
GLuint id ;
unsigned width = 0 ;
unsigned height = 0 ;
const void * pixels = NULL ;
2015-12-20 20:52:23 +01:00
/* Generate the OpenGL texture object */
2020-02-18 04:18:31 +01:00
glGenTextures ( 1 , & id ) ;
* idptr = id ;
if ( ti )
{
width = ti - > width ;
height = ti - > height ;
pixels = ti - > pixels ;
}
gl_load_texture_data ( id ,
2015-12-20 20:52:23 +01:00
RARCH_WRAP_EDGE , filter_type ,
4 /* TODO/FIXME - dehardcode */ ,
2020-02-18 04:18:31 +01:00
width , height , pixels ,
2015-12-20 20:52:23 +01:00
sizeof ( uint32_t ) /* TODO/FIXME - dehardcode */
) ;
}
2016-05-11 10:10:30 +02:00
# ifdef HAVE_THREADS
2019-02-06 19:43:31 +01:00
static int video_texture_load_wrap_gl2_mipmap ( void * data )
2015-12-20 20:52:23 +01:00
{
uintptr_t id = 0 ;
if ( ! data )
return 0 ;
2019-02-06 19:49:45 +01:00
video_texture_load_gl2 ( ( struct texture_image * ) data ,
2016-02-14 16:59:21 +01:00
TEXTURE_FILTER_MIPMAP_LINEAR , & id ) ;
2018-11-26 18:09:57 +01:00
return ( int ) id ;
2015-12-20 20:52:23 +01:00
}
2019-02-06 19:49:45 +01:00
static int video_texture_load_wrap_gl2 ( void * data )
2015-12-20 20:52:23 +01:00
{
uintptr_t id = 0 ;
if ( ! data )
return 0 ;
2019-02-06 19:49:45 +01:00
video_texture_load_gl2 ( ( struct texture_image * ) data ,
2016-02-14 16:59:21 +01:00
TEXTURE_FILTER_LINEAR , & id ) ;
2018-11-26 18:09:57 +01:00
return ( int ) id ;
2015-12-20 20:52:23 +01:00
}
2016-05-11 10:10:30 +02:00
# endif
2015-12-20 20:52:23 +01:00
2019-02-06 19:43:31 +01:00
static uintptr_t gl2_load_texture ( void * video_data , void * data ,
2015-12-20 20:52:23 +01:00
bool threaded , enum texture_filter_type filter_type )
{
uintptr_t id = 0 ;
2019-01-20 20:06:14 +01:00
2016-03-13 15:30:30 +01:00
# ifdef HAVE_THREADS
2015-12-20 20:52:23 +01:00
if ( threaded )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) video_data ;
2019-02-06 19:49:45 +01:00
custom_command_method_t func = video_texture_load_wrap_gl2 ;
2015-12-20 20:52:23 +01:00
2020-07-27 10:26:13 +02:00
if ( gl - > ctx_driver - > make_current )
gl - > ctx_driver - > make_current ( false ) ;
2015-12-20 20:52:23 +01:00
switch ( filter_type )
{
case TEXTURE_FILTER_MIPMAP_LINEAR :
case TEXTURE_FILTER_MIPMAP_NEAREST :
2019-02-06 19:43:31 +01:00
func = video_texture_load_wrap_gl2_mipmap ;
2015-12-20 20:52:23 +01:00
break ;
default :
break ;
}
2019-01-20 20:06:14 +01:00
return video_thread_texture_load ( data , func ) ;
2015-12-20 20:52:23 +01:00
}
2016-03-13 15:30:30 +01:00
# endif
2015-12-20 20:52:23 +01:00
2019-02-06 19:49:45 +01:00
video_texture_load_gl2 ( ( struct texture_image * ) data , filter_type , & id ) ;
2015-12-20 20:52:23 +01:00
return id ;
}
2020-07-27 10:15:28 +02:00
static void gl2_unload_texture ( void * data ,
bool threaded , uintptr_t id )
2015-12-20 20:52:23 +01:00
{
2019-01-20 20:06:14 +01:00
GLuint glid ;
if ( ! id )
2015-12-20 20:52:23 +01:00
return ;
2019-01-13 19:12:10 +01:00
2020-07-27 10:26:13 +02:00
# ifdef HAVE_THREADS
if ( threaded )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-10-16 00:24:32 +02:00
if ( gl & & gl - > ctx_driver )
if ( gl - > ctx_driver - > make_current )
gl - > ctx_driver - > make_current ( false ) ;
2020-07-27 10:26:13 +02:00
}
# endif
2019-01-20 20:06:14 +01:00
glid = ( GLuint ) id ;
glDeleteTextures ( 1 , & glid ) ;
2015-12-20 20:52:23 +01:00
}
2019-02-06 19:43:31 +01:00
static float gl2_get_refresh_rate ( void * data )
2018-04-15 17:38:00 -05:00
{
2018-04-21 15:00:35 +02:00
float refresh_rate = 0.0f ;
if ( video_context_driver_get_refresh_rate ( & refresh_rate ) )
return refresh_rate ;
return 0.0f ;
2018-04-15 17:38:00 -05:00
}
2019-02-06 19:43:31 +01:00
static uint32_t gl2_get_flags ( void * data )
2018-04-23 13:42:09 +02:00
{
2019-03-13 12:11:31 +01:00
uint32_t flags = 0 ;
2018-04-23 13:42:09 +02:00
2018-04-26 20:45:01 +02:00
BIT32_SET ( flags , GFX_CTX_FLAGS_HARD_SYNC ) ;
2018-04-23 14:15:21 +02:00
BIT32_SET ( flags , GFX_CTX_FLAGS_BLACK_FRAME_INSERTION ) ;
2018-04-24 15:14:06 +02:00
BIT32_SET ( flags , GFX_CTX_FLAGS_MENU_FRAME_FILTERING ) ;
2019-05-05 13:46:26 +02:00
BIT32_SET ( flags , GFX_CTX_FLAGS_SCREENSHOTS_SUPPORTED ) ;
2021-12-26 05:56:44 +02:00
BIT32_SET ( flags , GFX_CTX_FLAGS_OVERLAY_BEHIND_MENU_SUPPORTED ) ;
2018-04-23 14:15:21 +02:00
2018-04-23 13:42:09 +02:00
return flags ;
}
2019-02-06 19:43:31 +01:00
static const video_poke_interface_t gl2_poke_interface = {
gl2_get_flags ,
gl2_load_texture ,
gl2_unload_texture ,
gl2_set_video_mode ,
gl2_get_refresh_rate ,
2013-04-20 10:56:04 +02:00
NULL ,
2019-02-06 19:43:31 +01:00
gl2_get_video_output_size ,
gl2_get_video_output_prev ,
gl2_get_video_output_next ,
gl2_get_current_framebuffer ,
gl2_get_proc_address ,
gl2_set_aspect_ratio ,
gl2_apply_state_changes ,
gl2_set_texture_frame ,
gl2_set_texture_enable ,
2020-01-04 16:24:14 +01:00
font_driver_render_msg ,
2019-02-06 19:43:31 +01:00
gl2_show_mouse ,
2015-10-28 00:55:11 +01:00
NULL ,
2019-02-06 19:43:31 +01:00
gl2_get_current_shader ,
2018-01-30 22:29:57 +01:00
NULL , /* get_current_software_framebuffer */
2021-09-03 06:15:25 +02:00
NULL , /* get_hw_render_interface */
NULL , /* set_hdr_max_nits */
NULL , /* set_hdr_paper_white_nits */
NULL , /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
2013-03-10 01:16:56 +01:00
} ;
2019-02-06 19:43:31 +01:00
static void gl2_get_poke_interface ( void * data ,
2014-10-01 23:50:58 +02:00
const video_poke_interface_t * * iface )
2013-03-10 01:16:56 +01:00
{
2020-08-02 23:44:28 +02:00
( void ) data ;
2019-02-06 19:43:31 +01:00
* iface = & gl2_poke_interface ;
2013-03-10 01:16:56 +01:00
}
2020-02-17 21:28:42 +01:00
# ifdef HAVE_GFX_WIDGETS
2020-02-17 01:43:40 +01:00
static bool gl2_gfx_widgets_enabled ( void * data )
2018-11-22 15:45:52 +01:00
{
( void ) data ;
return true ;
}
# endif
2020-07-27 13:39:02 +02:00
static bool gl2_has_windowed ( void * data )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-07-27 13:39:02 +02:00
if ( gl & & gl - > ctx_driver )
return gl - > ctx_driver - > has_windowed ;
return false ;
}
2020-07-27 13:46:55 +02:00
static bool gl2_focus ( void * data )
{
2021-09-26 17:42:12 +02:00
gl2_t * gl = ( gl2_t * ) data ;
2020-07-27 13:46:55 +02:00
if ( gl & & gl - > ctx_driver & & gl - > ctx_driver - > has_focus )
return gl - > ctx_driver - > has_focus ( gl - > ctx_data ) ;
return true ;
}
2019-02-06 19:43:31 +01:00
video_driver_t video_gl2 = {
gl2_init ,
gl2_frame ,
gl2_set_nonblock_state ,
gl2_alive ,
2020-07-27 13:46:55 +02:00
gl2_focus ,
2019-02-06 19:43:31 +01:00
gl2_suppress_screensaver ,
2020-07-27 13:39:02 +02:00
gl2_has_windowed ,
2012-05-27 23:16:22 +02:00
2019-02-06 19:43:31 +01:00
gl2_set_shader ,
2012-05-27 23:16:22 +02:00
2019-02-06 19:43:31 +01:00
gl2_free ,
2012-05-27 22:50:03 +02:00
" gl " ,
2012-05-27 23:16:22 +02:00
2019-02-06 19:43:31 +01:00
gl2_set_viewport_wrapper ,
gl2_set_rotation ,
2012-06-09 00:24:43 +02:00
2019-02-06 19:43:31 +01:00
gl2_viewport_info ,
2014-01-05 22:21:11 +01:00
2019-02-06 19:43:31 +01:00
gl2_read_viewport ,
2015-03-16 13:39:25 +01:00
# if defined(READ_RAW_GL_FRAME_TEST)
2019-02-06 19:43:31 +01:00
gl2_read_frame_raw ,
2015-03-16 13:39:25 +01:00
# else
NULL ,
# endif
2012-12-20 11:16:22 +01:00
2012-12-23 18:36:58 +01:00
# ifdef HAVE_OVERLAY
2019-02-06 19:43:31 +01:00
gl2_get_overlay_interface ,
2019-04-01 04:00:58 +01:00
# endif
# ifdef HAVE_VIDEO_LAYOUT
2019-04-03 05:04:17 +01:00
gl2_get_video_layout_render_interface ,
2012-12-23 18:36:58 +01:00
# endif
2019-02-06 19:43:31 +01:00
gl2_get_poke_interface ,
gl2_wrap_type_to_enum ,
2020-02-17 21:28:42 +01:00
# ifdef HAVE_GFX_WIDGETS
2020-02-17 01:43:40 +01:00
gl2_gfx_widgets_enabled
2018-11-22 15:45:52 +01:00
# endif
2010-05-28 02:45:18 +02:00
} ;