2015-05-24 04:55:12 +00:00
// Copyright 2008 Dolphin Emulator Project
2015-05-17 23:08:10 +00:00
// Licensed under GPLv2+
2013-04-18 03:29:41 +00:00
// Refer to the license.txt file included.
2009-02-23 07:23:34 +00:00
2014-08-17 03:00:57 +00:00
# include <algorithm>
2014-02-17 10:18:15 +00:00
# include <cinttypes>
2009-02-23 07:23:34 +00:00
# include <cmath>
2009-03-28 21:07:16 +00:00
# include <cstdio>
2015-05-08 13:28:29 +00:00
# include <memory>
2014-03-12 19:33:41 +00:00
# include <string>
2014-02-17 10:18:15 +00:00
# include <vector>
# include "Common/Atomic.h"
2016-01-02 20:01:12 +00:00
# include "Common/CommonTypes.h"
2014-02-17 10:18:15 +00:00
# include "Common/FileUtil.h"
2015-05-06 22:37:58 +00:00
# include "Common/MathUtil.h"
2014-02-17 10:18:15 +00:00
# include "Common/StringUtil.h"
2015-09-18 16:40:00 +00:00
# include "Common/GL/GLInterfaceBase.h"
# include "Common/GL/GLUtil.h"
2014-12-28 20:46:00 +00:00
# include "Common/Logging/LogManager.h"
2014-02-17 10:18:15 +00:00
# include "Core/ConfigManager.h"
# include "Core/Core.h"
2014-11-13 22:26:49 +00:00
# include "VideoBackends/OGL/BoundingBox.h"
2014-02-17 10:18:15 +00:00
# include "VideoBackends/OGL/FramebufferManager.h"
# include "VideoBackends/OGL/PostProcessing.h"
# include "VideoBackends/OGL/ProgramShaderCache.h"
# include "VideoBackends/OGL/RasterFont.h"
# include "VideoBackends/OGL/Render.h"
# include "VideoBackends/OGL/SamplerCache.h"
# include "VideoBackends/OGL/TextureCache.h"
# include "VideoBackends/OGL/VertexManager.h"
2016-01-02 18:07:08 +00:00
# if defined(HAVE_LIBAV) || defined (_WIN32)
# include "VideoCommon/AVIDump.h"
# endif
2014-02-17 10:18:15 +00:00
# include "VideoCommon/BPFunctions.h"
# include "VideoCommon/DriverDetails.h"
# include "VideoCommon/Fifo.h"
# include "VideoCommon/ImageWrite.h"
# include "VideoCommon/OnScreenDisplay.h"
# include "VideoCommon/PixelEngine.h"
2015-01-02 17:06:56 +00:00
# include "VideoCommon/PixelShaderManager.h"
2014-02-17 10:18:15 +00:00
# include "VideoCommon/VertexShaderManager.h"
# include "VideoCommon/VideoConfig.h"
2009-02-23 07:23:34 +00:00
2011-01-29 20:16:51 +00:00
void VideoConfig : : UpdateProjectionHack ( )
{
2011-01-29 21:13:56 +00:00
: : UpdateProjectionHack ( g_Config . iPhackvalue , g_Config . sPhackvalue ) ;
2011-01-29 20:16:51 +00:00
}
2014-07-08 13:58:25 +00:00
static int OSDInternalW , OSDInternalH ;
2011-01-29 20:16:51 +00:00
namespace OGL
{
2013-03-25 14:45:10 +00:00
2013-03-25 14:14:24 +00:00
VideoConfig g_ogl_config ;
2011-01-29 20:16:51 +00:00
// Declarations and definitions
// ----------------------------
2015-12-22 23:47:20 +00:00
static std : : unique_ptr < RasterFont > s_raster_font ;
2009-02-23 07:23:34 +00:00
2009-03-08 19:19:51 +00:00
// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
static int s_MSAASamples = 1 ;
2015-12-12 12:00:08 +00:00
static int s_last_multisamples = 1 ;
2014-12-28 17:35:23 +00:00
static bool s_last_stereo_mode = false ;
2014-12-28 17:26:25 +00:00
static bool s_last_xfb_mode = false ;
2014-10-29 14:42:37 +00:00
2009-03-08 19:19:51 +00:00
static u32 s_blendMode ;
2009-02-23 07:23:34 +00:00
2013-03-30 21:17:39 +00:00
static bool s_vsync ;
2011-08-22 04:15:02 +00:00
// EFB cache related
2012-12-07 22:34:38 +00:00
static const u32 EFB_CACHE_RECT_SIZE = 64 ; // Cache 64x64 blocks.
static const u32 EFB_CACHE_WIDTH = ( EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1 ) / EFB_CACHE_RECT_SIZE ; // round up
static const u32 EFB_CACHE_HEIGHT = ( EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1 ) / EFB_CACHE_RECT_SIZE ;
2011-08-22 04:15:02 +00:00
static bool s_efbCacheValid [ 2 ] [ EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT ] ;
2014-06-05 08:12:05 +00:00
static bool s_efbCacheIsCleared = false ;
2011-08-22 04:15:02 +00:00
static std : : vector < u32 > s_efbCache [ 2 ] [ EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT ] ; // 2 for PEEK_Z and PEEK_COLOR
2009-07-29 03:11:35 +00:00
2016-01-01 19:58:19 +00:00
static void APIENTRY ErrorCallback ( GLenum source , GLenum type , GLuint id , GLenum severity , GLsizei length , const char * message , const void * userParam )
2013-04-04 15:37:16 +00:00
{
const char * s_source ;
const char * s_type ;
2013-05-06 04:33:49 +00:00
2014-03-10 11:30:55 +00:00
switch ( source )
2013-04-04 15:37:16 +00:00
{
case GL_DEBUG_SOURCE_API_ARB : s_source = " API " ; break ;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB : s_source = " Window System " ; break ;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB : s_source = " Shader Compiler " ; break ;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB : s_source = " Third Party " ; break ;
case GL_DEBUG_SOURCE_APPLICATION_ARB : s_source = " Application " ; break ;
case GL_DEBUG_SOURCE_OTHER_ARB : s_source = " Other " ; break ;
default : s_source = " Unknown " ; break ;
}
2014-03-10 11:30:55 +00:00
switch ( type )
2013-04-04 15:37:16 +00:00
{
case GL_DEBUG_TYPE_ERROR_ARB : s_type = " Error " ; break ;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB : s_type = " Deprecated " ; break ;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB : s_type = " Undefined " ; break ;
case GL_DEBUG_TYPE_PORTABILITY_ARB : s_type = " Portability " ; break ;
case GL_DEBUG_TYPE_PERFORMANCE_ARB : s_type = " Performance " ; break ;
case GL_DEBUG_TYPE_OTHER_ARB : s_type = " Other " ; break ;
default : s_type = " Unknown " ; break ;
}
2014-03-10 11:30:55 +00:00
switch ( severity )
2013-04-04 15:37:16 +00:00
{
2015-09-10 06:27:31 +00:00
case GL_DEBUG_SEVERITY_HIGH_ARB : ERROR_LOG ( HOST_GPU , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
case GL_DEBUG_SEVERITY_MEDIUM_ARB : WARN_LOG ( HOST_GPU , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
case GL_DEBUG_SEVERITY_LOW_ARB : WARN_LOG ( HOST_GPU , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
case GL_DEBUG_SEVERITY_NOTIFICATION : DEBUG_LOG ( HOST_GPU , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
default : ERROR_LOG ( HOST_GPU , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
2013-04-04 15:37:16 +00:00
}
}
2013-06-25 16:14:41 +00:00
// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
2016-01-01 19:58:19 +00:00
static void APIENTRY DepthRangef ( GLfloat neardepth , GLfloat fardepth )
2013-06-25 16:14:41 +00:00
{
2014-01-01 22:02:18 +00:00
glDepthRange ( neardepth , fardepth ) ;
2013-06-25 16:14:41 +00:00
}
2016-01-01 19:58:19 +00:00
static void APIENTRY ClearDepthf ( GLfloat depthval )
2013-06-25 16:14:41 +00:00
{
2014-01-01 22:02:18 +00:00
glClearDepth ( depthval ) ;
2013-06-25 16:14:41 +00:00
}
2014-07-08 12:29:26 +00:00
static void InitDriverInfo ( )
2013-06-11 13:33:56 +00:00
{
std : : string svendor = std : : string ( g_ogl_config . gl_vendor ) ;
std : : string srenderer = std : : string ( g_ogl_config . gl_renderer ) ;
2013-08-23 08:52:29 +00:00
std : : string sversion = std : : string ( g_ogl_config . gl_version ) ;
2013-06-11 13:33:56 +00:00
DriverDetails : : Vendor vendor = DriverDetails : : VENDOR_UNKNOWN ;
2013-08-21 10:34:42 +00:00
DriverDetails : : Driver driver = DriverDetails : : DRIVER_UNKNOWN ;
2016-01-15 18:13:14 +00:00
DriverDetails : : Family family = DriverDetails : : Family : : UNKNOWN ;
2013-06-11 13:33:56 +00:00
double version = 0.0 ;
2013-08-21 10:34:42 +00:00
// Get the vendor first
2013-06-11 13:33:56 +00:00
if ( svendor = = " NVIDIA Corporation " & & srenderer ! = " NVIDIA Tegra " )
2014-08-15 18:09:53 +00:00
{
2013-10-29 05:23:17 +00:00
vendor = DriverDetails : : VENDOR_NVIDIA ;
2014-08-15 18:09:53 +00:00
}
2013-08-21 10:34:42 +00:00
else if ( svendor = = " ATI Technologies Inc. " | | svendor = = " Advanced Micro Devices, Inc. " )
2014-08-15 18:09:53 +00:00
{
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_ATI ;
2014-08-15 18:09:53 +00:00
}
2013-08-23 08:52:29 +00:00
else if ( std : : string : : npos ! = sversion . find ( " Mesa " ) )
2014-08-15 18:09:53 +00:00
{
2013-08-23 08:52:29 +00:00
vendor = DriverDetails : : VENDOR_MESA ;
2014-08-15 18:09:53 +00:00
}
2013-06-11 13:33:56 +00:00
else if ( std : : string : : npos ! = svendor . find ( " Intel " ) )
2014-08-15 18:09:53 +00:00
{
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_INTEL ;
2014-08-15 18:09:53 +00:00
}
2013-06-11 13:33:56 +00:00
else if ( svendor = = " ARM " )
2014-08-15 18:09:53 +00:00
{
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_ARM ;
2014-08-15 18:09:53 +00:00
}
2013-08-21 10:41:32 +00:00
else if ( svendor = = " http://limadriver.org/ " )
{
vendor = DriverDetails : : VENDOR_ARM ;
driver = DriverDetails : : DRIVER_LIMA ;
}
2013-06-11 13:33:56 +00:00
else if ( svendor = = " Qualcomm " )
2014-08-15 18:09:53 +00:00
{
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_QUALCOMM ;
2014-08-15 18:09:53 +00:00
}
2013-06-11 13:33:56 +00:00
else if ( svendor = = " Imagination Technologies " )
2014-08-15 18:09:53 +00:00
{
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_IMGTEC ;
2014-08-15 18:09:53 +00:00
}
2013-07-03 01:58:09 +00:00
else if ( svendor = = " NVIDIA Corporation " & & srenderer = = " NVIDIA Tegra " )
2014-08-15 18:09:53 +00:00
{
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_TEGRA ;
2014-08-15 18:09:53 +00:00
}
2013-06-11 13:33:56 +00:00
else if ( svendor = = " Vivante Corporation " )
2014-08-15 18:09:53 +00:00
{
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_VIVANTE ;
2014-08-15 18:09:53 +00:00
}
2013-10-29 05:23:17 +00:00
2013-06-11 13:33:56 +00:00
// Get device family and driver version...if we care about it
2014-03-10 11:30:55 +00:00
switch ( vendor )
2013-06-11 13:33:56 +00:00
{
case DriverDetails : : VENDOR_QUALCOMM :
{
2014-12-19 21:31:37 +00:00
driver = DriverDetails : : DRIVER_QUALCOMM ;
2013-06-11 13:33:56 +00:00
double glVersion ;
sscanf ( g_ogl_config . gl_version , " OpenGL ES %lg V@%lg " , & glVersion , & version ) ;
}
break ;
2013-07-25 05:44:01 +00:00
case DriverDetails : : VENDOR_ARM :
2014-04-12 04:46:44 +00:00
// Currently the Mali-T line has two families in it.
// Mali-T6xx and Mali-T7xx
// These two families are similar enough that they share bugs in their drivers.
2014-12-19 21:41:12 +00:00
//
// Mali drivers provide no way to explicitly find out what video driver is running.
// This is similar to how we can't find the Nvidia driver version in Windows.
// Good thing is that ARM introduces a new video driver about once every two years so we can
// find the driver version by the features it exposes.
// r2p0 - No OpenGL ES 3.0 support (We don't support this)
// r3p0 - OpenGL ES 3.0 support
// r4p0 - Supports 'GL_EXT_shader_pixel_local_storage' extension.
driver = DriverDetails : : DRIVER_ARM ;
if ( GLExtensions : : Supports ( " GL_EXT_shader_pixel_local_storage " ) )
version = 400 ;
else
version = 300 ;
2013-08-23 08:52:29 +00:00
break ;
case DriverDetails : : VENDOR_MESA :
{
2014-03-10 11:30:55 +00:00
if ( svendor = = " nouveau " )
2016-01-15 18:13:14 +00:00
{
2013-08-23 08:52:29 +00:00
driver = DriverDetails : : DRIVER_NOUVEAU ;
2016-01-15 18:13:14 +00:00
}
2014-03-10 11:30:55 +00:00
else if ( svendor = = " Intel Open Source Technology Center " )
2016-01-15 18:13:14 +00:00
{
2013-08-23 08:52:29 +00:00
driver = DriverDetails : : DRIVER_I965 ;
2016-01-15 18:13:14 +00:00
if ( srenderer . find ( " Sandybridge " ) ! = std : : string : : npos )
family = DriverDetails : : Family : : INTEL_SANDY ;
else if ( srenderer . find ( " Ivybridge " ) ! = std : : string : : npos )
family = DriverDetails : : Family : : INTEL_IVY ;
}
2014-03-10 11:30:55 +00:00
else if ( std : : string : : npos ! = srenderer . find ( " AMD " ) | | std : : string : : npos ! = srenderer . find ( " ATI " ) )
2016-01-15 18:13:14 +00:00
{
2013-08-23 08:52:29 +00:00
driver = DriverDetails : : DRIVER_R600 ;
2016-01-15 18:13:14 +00:00
}
2013-10-29 05:23:17 +00:00
2013-08-23 08:52:29 +00:00
int major = 0 ;
int minor = 0 ;
int release = 0 ;
2015-07-25 10:20:00 +00:00
sscanf ( g_ogl_config . gl_version , " %*s (Core Profile) Mesa %d.%d.%d " , & major , & minor , & release ) ;
2013-08-23 08:52:29 +00:00
version = 100 * major + 10 * minor + release ;
}
2013-07-25 05:44:01 +00:00
break ;
2014-09-04 23:03:53 +00:00
case DriverDetails : : VENDOR_INTEL : // Happens in OS X/Windows
{
2016-01-15 18:13:14 +00:00
u32 market_name ;
sscanf ( g_ogl_config . gl_renderer , " Intel HD Graphics %d " , & market_name ) ;
switch ( market_name )
{
case 2000 :
case 3000 :
family = DriverDetails : : Family : : INTEL_SANDY ;
break ;
case 2500 :
case 4000 :
family = DriverDetails : : Family : : INTEL_IVY ;
break ;
default :
family = DriverDetails : : Family : : UNKNOWN ;
break ;
} ;
2014-09-04 23:03:53 +00:00
# ifdef _WIN32
2013-12-31 00:26:55 +00:00
int glmajor = 0 ;
int glminor = 0 ;
int major = 0 ;
int minor = 0 ;
int release = 0 ;
2014-09-04 23:03:53 +00:00
int revision = 0 ;
// Example version string: '4.3.0 - Build 10.18.10.3907'
sscanf ( g_ogl_config . gl_version , " %d.%d.0 - Build %d.%d.%d.%d " , & glmajor , & glminor , & major , & minor , & release , & revision ) ;
version = 100000000 * major + 1000000 * minor + 10000 * release + revision ;
version / = 10000 ;
# endif
}
2013-12-31 00:26:55 +00:00
break ;
2014-01-08 00:29:04 +00:00
case DriverDetails : : VENDOR_NVIDIA :
{
int glmajor = 0 ;
int glminor = 0 ;
int glrelease = 0 ;
int major = 0 ;
int minor = 0 ;
2015-01-11 05:17:29 +00:00
// TODO: this is known to be broken on Windows
// Nvidia seems to have removed their driver version from this string, so we can't get it.
// hopefully we'll never have to workaround Nvidia bugs
2014-01-08 01:35:06 +00:00
sscanf ( g_ogl_config . gl_version , " %d.%d.%d NVIDIA %d.%d " , & glmajor , & glminor , & glrelease , & major , & minor ) ;
2014-01-08 00:29:04 +00:00
version = 100 * major + minor ;
}
break ;
2013-06-11 13:33:56 +00:00
// We don't care about these
default :
break ;
}
2013-12-31 00:26:55 +00:00
DriverDetails : : Init ( vendor , driver , version , family ) ;
2013-06-11 13:33:56 +00:00
}
2011-05-07 22:00:05 +00:00
// Init functions
Renderer : : Renderer ( )
{
OSDInternalW = 0 ;
OSDInternalH = 0 ;
s_blendMode = 0 ;
2009-04-03 20:22:45 +00:00
2011-05-07 22:00:05 +00:00
bool bSuccess = true ;
2013-05-06 04:33:49 +00:00
// Init extension support.
2013-12-30 13:22:50 +00:00
if ( ! GLExtensions : : Init ( ) )
2013-09-02 11:14:45 +00:00
{
2013-12-30 13:22:50 +00:00
// OpenGL 2.0 is required for all shader based drawings. There is no way to get this by extensions
PanicAlert ( " GPU: OGL ERROR: Does your video card support OpenGL 2.0? " ) ;
bSuccess = false ;
2013-09-02 11:14:45 +00:00
}
2014-01-02 02:06:11 +00:00
g_ogl_config . gl_vendor = ( const char * ) glGetString ( GL_VENDOR ) ;
g_ogl_config . gl_renderer = ( const char * ) glGetString ( GL_RENDERER ) ;
g_ogl_config . gl_version = ( const char * ) glGetString ( GL_VERSION ) ;
g_ogl_config . glsl_version = ( const char * ) glGetString ( GL_SHADING_LANGUAGE_VERSION ) ;
InitDriverInfo ( ) ;
2014-03-29 10:05:44 +00:00
2015-12-13 17:39:45 +00:00
if ( GLExtensions : : Version ( ) < 300 )
{
// integer vertex attributes require a gl3 only function
PanicAlert ( " GPU: OGL ERROR: Need OpenGL version 3. \n "
" GPU: Does your video card support OpenGL 3? " ) ;
bSuccess = false ;
}
2013-09-02 11:14:45 +00:00
// check for the max vertex attributes
2011-05-07 22:00:05 +00:00
GLint numvertexattribs = 0 ;
2009-02-28 16:33:59 +00:00
glGetIntegerv ( GL_MAX_VERTEX_ATTRIBS , & numvertexattribs ) ;
2013-01-21 09:37:16 +00:00
if ( numvertexattribs < 16 )
2010-08-10 01:08:22 +00:00
{
2013-09-02 11:14:45 +00:00
PanicAlert ( " GPU: OGL ERROR: Number of attributes %d not enough. \n "
2010-08-10 01:08:22 +00:00
" GPU: Does your video card support OpenGL 2.x? " ,
numvertexattribs ) ;
2010-06-05 01:38:22 +00:00
bSuccess = false ;
}
2013-09-02 11:14:45 +00:00
// check the max texture width and height
GLint max_texture_size ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , ( GLint * ) & max_texture_size ) ;
if ( max_texture_size < 1024 )
2010-08-10 01:08:22 +00:00
{
2013-09-02 11:14:45 +00:00
PanicAlert ( " GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024. " ,
max_texture_size ) ;
bSuccess = false ;
2010-06-05 01:38:22 +00:00
}
2013-10-29 05:23:17 +00:00
2015-12-13 17:39:45 +00:00
if ( GLInterface - > GetMode ( ) = = GLInterfaceMode : : MODE_OPENGL )
2010-08-10 01:08:22 +00:00
{
2015-12-13 17:39:45 +00:00
if ( ! GLExtensions : : Supports ( " GL_ARB_framebuffer_object " ) )
{
// We want the ogl3 framebuffer instead of the ogl2 one for better blitting support.
// It's also compatible with the gles3 one.
PanicAlert ( " GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets. \n "
" GPU: Does your video card support OpenGL 3.0? " ) ;
bSuccess = false ;
}
2013-10-29 05:23:17 +00:00
2015-12-13 17:39:45 +00:00
if ( ! GLExtensions : : Supports ( " GL_ARB_vertex_array_object " ) )
{
// This extension is used to replace lots of pointer setting function.
// Also gles3 requires to use it.
PanicAlert ( " GPU: OGL ERROR: Need GL_ARB_vertex_array_object. \n "
" GPU: Does your video card support OpenGL 3.0? " ) ;
bSuccess = false ;
}
2012-12-15 13:43:01 +00:00
2015-12-13 17:39:45 +00:00
if ( ! GLExtensions : : Supports ( " GL_ARB_map_buffer_range " ) )
{
// ogl3 buffer mapping for better streaming support.
// The ogl2 one also isn't in gles3.
PanicAlert ( " GPU: OGL ERROR: Need GL_ARB_map_buffer_range. \n "
" GPU: Does your video card support OpenGL 3.0? " ) ;
bSuccess = false ;
}
2014-01-30 15:38:11 +00:00
2015-12-13 17:39:45 +00:00
if ( ! GLExtensions : : Supports ( " GL_ARB_uniform_buffer_object " ) )
{
// ubo allow us to keep the current constants on shader switches
// we also can stream them much nicer and pack into it whatever we want to
PanicAlert ( " GPU: OGL ERROR: Need GL_ARB_uniform_buffer_object. \n "
" GPU: Does your video card support OpenGL 3.1? " ) ;
bSuccess = false ;
}
else if ( DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENUBO ) )
{
PanicAlert ( " Buggy GPU driver detected. \n "
" Please either install the closed-source GPU driver or update your Mesa 3D version. " ) ;
bSuccess = false ;
}
2014-11-26 20:33:47 +00:00
2015-12-13 17:39:45 +00:00
if ( ! GLExtensions : : Supports ( " GL_ARB_sampler_objects " ) )
{
// Our sampler cache uses this extension. It could easyly be workaround and it's by far the
// highest requirement, but it seems that no driver lacks support for it.
PanicAlert ( " GPU: OGL ERROR: Need GL_ARB_sampler_objects. \n "
" GPU: Does your video card support OpenGL 3.3? " ) ;
bSuccess = false ;
}
2013-10-29 05:23:17 +00:00
2015-12-13 17:39:45 +00:00
// OpenGL 3 doesn't provide GLES like float functions for depth.
// They are in core in OpenGL 4.1, so almost every driver should support them.
// But for the oldest ones, we provide fallbacks to the old double functions.
if ( ! GLExtensions : : Supports ( " GL_ARB_ES2_compatibility " ) )
{
glDepthRangef = DepthRangef ;
glClearDepthf = ClearDepthf ;
}
2013-06-25 16:14:41 +00:00
}
2014-01-02 02:06:11 +00:00
2015-09-05 01:25:59 +00:00
g_Config . backend_info . bSupportsDualSourceBlend = GLExtensions : : Supports ( " GL_ARB_blend_func_extended " ) | |
GLExtensions : : Supports ( " GL_EXT_blend_func_extended " ) ;
2014-01-17 15:10:10 +00:00
g_Config . backend_info . bSupportsPrimitiveRestart = ! DriverDetails : : HasBug ( DriverDetails : : BUG_PRIMITIVERESTART ) & &
( ( GLExtensions : : Version ( ) > = 310 ) | | GLExtensions : : Supports ( " GL_NV_primitive_restart " ) ) ;
2014-11-13 22:26:49 +00:00
g_Config . backend_info . bSupportsBBox = GLExtensions : : Supports ( " GL_ARB_shader_storage_buffer_object " ) ;
2014-10-29 13:51:12 +00:00
g_Config . backend_info . bSupportsGSInstancing = GLExtensions : : Supports ( " GL_ARB_gpu_shader5 " ) ;
2015-09-07 20:21:11 +00:00
g_Config . backend_info . bSupportsSSAA = GLExtensions : : Supports ( " GL_ARB_gpu_shader5 " ) & & GLExtensions : : Supports ( " GL_ARB_sample_shading " ) ;
2016-01-09 18:07:08 +00:00
g_Config . backend_info . bSupportsGeometryShaders = GLExtensions : : Version ( ) > = 320 & & ! DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENGEOMETRYSHADERS ) ;
2015-09-01 10:23:43 +00:00
g_Config . backend_info . bSupportsPaletteConversion = GLExtensions : : Supports ( " GL_ARB_texture_buffer_object " ) | |
GLExtensions : : Supports ( " GL_OES_texture_buffer " ) | |
GLExtensions : : Supports ( " GL_EXT_texture_buffer " ) ;
2015-05-18 23:18:04 +00:00
g_Config . backend_info . bSupportsClipControl = GLExtensions : : Supports ( " GL_ARB_clip_control " ) ;
2015-07-25 10:20:00 +00:00
g_ogl_config . bSupportsCopySubImage = ( GLExtensions : : Supports ( " GL_ARB_copy_image " ) | |
GLExtensions : : Supports ( " GL_NV_copy_image " ) | |
GLExtensions : : Supports ( " GL_EXT_copy_image " ) | |
GLExtensions : : Supports ( " GL_OES_copy_image " ) ) & &
! DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENCOPYIMAGE ) ;
2014-03-30 18:58:05 +00:00
// Desktop OpenGL supports the binding layout if it supports 420pack
// OpenGL ES 3.1 supports it implicitly without an extension
g_Config . backend_info . bSupportsBindingLayout = GLExtensions : : Supports ( " GL_ARB_shading_language_420pack " ) ;
2013-12-30 13:22:50 +00:00
g_ogl_config . bSupportsGLSLCache = GLExtensions : : Supports ( " GL_ARB_get_program_binary " ) ;
g_ogl_config . bSupportsGLPinnedMemory = GLExtensions : : Supports ( " GL_AMD_pinned_memory " ) ;
g_ogl_config . bSupportsGLSync = GLExtensions : : Supports ( " GL_ARB_sync " ) ;
2014-11-22 00:52:39 +00:00
g_ogl_config . bSupportsGLBaseVertex = GLExtensions : : Supports ( " GL_ARB_draw_elements_base_vertex " ) | |
2015-01-18 21:23:51 +00:00
GLExtensions : : Supports ( " GL_EXT_draw_elements_base_vertex " ) | |
GLExtensions : : Supports ( " GL_OES_draw_elements_base_vertex " ) ;
g_ogl_config . bSupportsGLBufferStorage = GLExtensions : : Supports ( " GL_ARB_buffer_storage " ) | |
2015-05-18 22:54:00 +00:00
GLExtensions : : Supports ( " GL_EXT_buffer_storage " ) ;
2014-04-30 16:48:40 +00:00
g_ogl_config . bSupportsMSAA = GLExtensions : : Supports ( " GL_ARB_texture_multisample " ) ;
2013-12-30 13:22:50 +00:00
g_ogl_config . bSupportViewportFloat = GLExtensions : : Supports ( " GL_ARB_viewport_array " ) ;
2015-08-26 05:09:32 +00:00
g_ogl_config . bSupportsDebug = GLExtensions : : Supports ( " GL_KHR_debug " ) | |
GLExtensions : : Supports ( " GL_ARB_debug_output " ) ;
2015-09-01 05:17:24 +00:00
g_ogl_config . bSupports3DTextureStorage = GLExtensions : : Supports ( " GL_ARB_texture_storage_multisample " ) | |
GLExtensions : : Supports ( " GL_OES_texture_storage_multisample_2d_array " ) ;
g_ogl_config . bSupports2DTextureStorage = GLExtensions : : Supports ( " GL_ARB_texture_storage_multisample " ) ;
2015-10-17 11:43:22 +00:00
g_ogl_config . bSupportsEarlyFragmentTests = GLExtensions : : Supports ( " GL_ARB_shader_image_load_store " ) ;
g_ogl_config . bSupportsConservativeDepth = GLExtensions : : Supports ( " GL_ARB_conservative_depth " ) ;
2015-11-19 06:46:26 +00:00
g_ogl_config . bSupportsAniso = GLExtensions : : Supports ( " GL_EXT_texture_filter_anisotropic " ) ;
2013-12-30 13:22:50 +00:00
if ( GLInterface - > GetMode ( ) = = GLInterfaceMode : : MODE_OPENGLES3 )
2014-03-30 18:58:05 +00:00
{
2015-08-26 05:09:32 +00:00
g_ogl_config . SupportedESPointSize = GLExtensions : : Supports ( " GL_OES_geometry_point_size " ) ? 1 : GLExtensions : : Supports ( " GL_EXT_geometry_point_size " ) ? 2 : 0 ;
2015-09-01 10:23:43 +00:00
g_ogl_config . SupportedESTextureBuffer = GLExtensions : : Supports ( " VERSION_GLES_3_2 " ) ? ES_TEXBUF_TYPE : : TEXBUF_CORE :
GLExtensions : : Supports ( " GL_OES_texture_buffer " ) ? ES_TEXBUF_TYPE : : TEXBUF_OES :
GLExtensions : : Supports ( " GL_EXT_texture_buffer " ) ? ES_TEXBUF_TYPE : : TEXBUF_EXT : ES_TEXBUF_TYPE : : TEXBUF_NONE ;
2015-08-26 05:09:32 +00:00
2015-12-13 17:39:45 +00:00
g_ogl_config . bSupportsGLSLCache = true ;
g_ogl_config . bSupportsGLSync = true ;
2015-08-22 14:12:19 +00:00
if ( strstr ( g_ogl_config . glsl_version , " 3.0 " ) | | DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENGLES31 ) )
2014-03-30 18:58:05 +00:00
{
g_ogl_config . eSupportedGLSLVersion = GLSLES_300 ;
2014-12-07 05:29:36 +00:00
g_ogl_config . bSupportsAEP = false ;
2014-12-16 23:26:03 +00:00
g_Config . backend_info . bSupportsGeometryShaders = false ;
2014-03-30 18:58:05 +00:00
}
2015-08-26 05:09:32 +00:00
else if ( strstr ( g_ogl_config . glsl_version , " 3.1 " ) )
2014-03-30 18:58:05 +00:00
{
g_ogl_config . eSupportedGLSLVersion = GLSLES_310 ;
2014-12-07 05:29:36 +00:00
g_ogl_config . bSupportsAEP = GLExtensions : : Supports ( " GL_ANDROID_extension_pack_es31a " ) ;
2014-03-30 18:58:05 +00:00
g_Config . backend_info . bSupportsBindingLayout = true ;
2015-10-17 11:43:22 +00:00
g_ogl_config . bSupportsEarlyFragmentTests = true ;
2014-12-16 23:26:03 +00:00
g_Config . backend_info . bSupportsGeometryShaders = g_ogl_config . bSupportsAEP ;
2015-08-26 05:09:32 +00:00
g_Config . backend_info . bSupportsGSInstancing = g_Config . backend_info . bSupportsGeometryShaders & & g_ogl_config . SupportedESPointSize > 0 ;
2015-09-06 11:58:18 +00:00
g_Config . backend_info . bSupportsSSAA = g_ogl_config . bSupportsAEP ;
2015-09-07 17:07:27 +00:00
g_Config . backend_info . bSupportsBBox = true ;
2015-09-01 05:17:24 +00:00
g_ogl_config . bSupportsMSAA = true ;
g_ogl_config . bSupports2DTextureStorage = true ;
2015-12-12 12:00:08 +00:00
if ( g_ActiveConfig . iStereoMode > 0 & & g_ActiveConfig . iMultisamples > 1 & & ! g_ogl_config . bSupports3DTextureStorage )
2015-09-01 05:17:24 +00:00
{
// GLES 3.1 can't support stereo rendering and MSAA
OSD : : AddMessage ( " MSAA Stereo rendering isn't supported by your GPU. " , 10000 ) ;
2015-12-12 12:00:08 +00:00
g_ActiveConfig . iMultisamples = 1 ;
2015-09-01 05:17:24 +00:00
}
2014-03-30 18:58:05 +00:00
}
2015-08-26 05:09:32 +00:00
else
{
g_ogl_config . eSupportedGLSLVersion = GLSLES_320 ;
g_ogl_config . bSupportsAEP = GLExtensions : : Supports ( " GL_ANDROID_extension_pack_es31a " ) ;
g_Config . backend_info . bSupportsBindingLayout = true ;
2015-10-17 11:43:22 +00:00
g_ogl_config . bSupportsEarlyFragmentTests = true ;
2015-08-26 05:09:32 +00:00
g_Config . backend_info . bSupportsGeometryShaders = true ;
g_Config . backend_info . bSupportsGSInstancing = g_ogl_config . SupportedESPointSize > 0 ;
2015-09-01 10:23:43 +00:00
g_Config . backend_info . bSupportsPaletteConversion = true ;
2015-09-01 05:17:24 +00:00
g_Config . backend_info . bSupportsSSAA = true ;
2015-09-07 17:07:27 +00:00
g_Config . backend_info . bSupportsBBox = true ;
2015-08-26 05:09:32 +00:00
g_ogl_config . bSupportsCopySubImage = true ;
g_ogl_config . bSupportsGLBaseVertex = true ;
g_ogl_config . bSupportsDebug = true ;
2015-09-01 05:17:24 +00:00
g_ogl_config . bSupportsMSAA = true ;
g_ogl_config . bSupports2DTextureStorage = true ;
g_ogl_config . bSupports3DTextureStorage = true ;
2015-08-26 05:09:32 +00:00
}
2014-03-30 18:58:05 +00:00
}
2013-12-30 13:22:50 +00:00
else
2013-04-08 12:50:58 +00:00
{
2014-03-10 11:30:55 +00:00
if ( strstr ( g_ogl_config . glsl_version , " 1.00 " ) | | strstr ( g_ogl_config . glsl_version , " 1.10 " ) | | strstr ( g_ogl_config . glsl_version , " 1.20 " ) )
2013-12-30 13:22:50 +00:00
{
PanicAlert ( " GPU: OGL ERROR: Need at least GLSL 1.30 \n "
" GPU: Does your video card support OpenGL 3.0? \n "
" GPU: Your driver supports GLSL %s " , g_ogl_config . glsl_version ) ;
bSuccess = false ;
}
2014-03-10 11:30:55 +00:00
else if ( strstr ( g_ogl_config . glsl_version , " 1.30 " ) )
2013-12-30 13:22:50 +00:00
{
g_ogl_config . eSupportedGLSLVersion = GLSL_130 ;
2015-10-17 11:43:22 +00:00
g_ogl_config . bSupportsEarlyFragmentTests = false ; // layout keyword is only supported on glsl150+
g_ogl_config . bSupportsConservativeDepth = false ; // layout keyword is only supported on glsl150+
2014-12-16 23:26:03 +00:00
g_Config . backend_info . bSupportsGeometryShaders = false ; // geometry shaders are only supported on glsl150+
2013-12-30 13:22:50 +00:00
}
2014-03-10 11:30:55 +00:00
else if ( strstr ( g_ogl_config . glsl_version , " 1.40 " ) )
2013-12-30 13:22:50 +00:00
{
g_ogl_config . eSupportedGLSLVersion = GLSL_140 ;
2015-10-17 11:43:22 +00:00
g_ogl_config . bSupportsEarlyFragmentTests = false ; // layout keyword is only supported on glsl150+
g_ogl_config . bSupportsConservativeDepth = false ; // layout keyword is only supported on glsl150+
2014-12-16 23:26:03 +00:00
g_Config . backend_info . bSupportsGeometryShaders = false ; // geometry shaders are only supported on glsl150+
2013-12-30 13:22:50 +00:00
}
2015-09-06 11:58:18 +00:00
else if ( strstr ( g_ogl_config . glsl_version , " 1.50 " ) )
2013-12-30 13:22:50 +00:00
{
g_ogl_config . eSupportedGLSLVersion = GLSL_150 ;
2015-09-06 11:58:18 +00:00
}
else if ( strstr ( g_ogl_config . glsl_version , " 3.30 " ) )
{
g_ogl_config . eSupportedGLSLVersion = GLSL_330 ;
}
else
{
g_ogl_config . eSupportedGLSLVersion = GLSL_400 ;
2015-09-07 20:21:11 +00:00
g_Config . backend_info . bSupportsSSAA = true ;
2013-12-30 13:22:50 +00:00
}
2014-12-07 05:29:36 +00:00
// Desktop OpenGL can't have the Android Extension Pack
g_ogl_config . bSupportsAEP = false ;
2013-04-08 12:50:58 +00:00
}
2014-11-22 14:07:52 +00:00
2015-10-17 11:43:22 +00:00
// Either method can do early-z tests. See PixelShaderGen for details.
g_Config . backend_info . bSupportsEarlyZ = g_ogl_config . bSupportsEarlyFragmentTests | | g_ogl_config . bSupportsConservativeDepth ;
2014-12-28 20:46:00 +00:00
if ( g_ogl_config . bSupportsDebug )
2013-04-08 12:50:58 +00:00
{
2014-12-28 20:46:00 +00:00
if ( GLExtensions : : Supports ( " GL_KHR_debug " ) )
{
glDebugMessageControl ( GL_DONT_CARE , GL_DONT_CARE , GL_DONT_CARE , 0 , nullptr , true ) ;
glDebugMessageCallback ( ErrorCallback , nullptr ) ;
}
else
{
glDebugMessageControlARB ( GL_DONT_CARE , GL_DONT_CARE , GL_DONT_CARE , 0 , nullptr , true ) ;
glDebugMessageCallbackARB ( ErrorCallback , nullptr ) ;
}
2015-09-10 06:27:31 +00:00
if ( LogManager : : GetInstance ( ) - > IsEnabled ( LogTypes : : HOST_GPU , LogTypes : : LERROR ) )
2014-12-28 20:46:00 +00:00
glEnable ( GL_DEBUG_OUTPUT ) ;
else
glDisable ( GL_DEBUG_OUTPUT ) ;
2013-04-08 12:50:58 +00:00
}
2014-11-22 14:07:52 +00:00
2013-11-05 16:37:32 +00:00
int samples ;
glGetIntegerv ( GL_SAMPLES , & samples ) ;
2014-03-10 11:30:55 +00:00
if ( samples > 1 )
2013-11-05 16:37:32 +00:00
{
// MSAA on default framebuffer isn't working because of glBlitFramebuffer.
// It also isn't useful as we don't render anything to the default framebuffer.
// We also try to get a non-msaa fb, so this only happens when forced by the driver.
PanicAlert ( " MSAA on default framebuffer isn't supported. \n "
2015-01-11 05:17:29 +00:00
" Please avoid forcing Dolphin to use MSAA by the driver. \n "
2013-11-05 16:37:32 +00:00
" %d samples on default framebuffer found. " , samples ) ;
bSuccess = false ;
}
2013-09-02 11:14:45 +00:00
if ( ! bSuccess )
{
// Not all needed extensions are supported, so we have to stop here.
// Else some of the next calls might crash.
return ;
}
2013-10-29 05:23:17 +00:00
2013-03-25 14:14:24 +00:00
glGetIntegerv ( GL_MAX_SAMPLES , & g_ogl_config . max_samples ) ;
2014-04-30 16:48:40 +00:00
if ( g_ogl_config . max_samples < 1 | | ! g_ogl_config . bSupportsMSAA )
2013-04-05 05:08:32 +00:00
g_ogl_config . max_samples = 1 ;
2013-10-29 05:23:17 +00:00
2014-10-30 13:56:40 +00:00
g_Config . VerifyValidity ( ) ;
2013-01-21 17:44:33 +00:00
UpdateActiveConfig ( ) ;
2013-03-25 14:14:24 +00:00
OSD : : AddMessage ( StringFromFormat ( " Video Info: %s, %s, %s " ,
g_ogl_config . gl_vendor ,
g_ogl_config . gl_renderer ,
2013-08-23 23:44:16 +00:00
g_ogl_config . gl_version ) , 5000 ) ;
2013-10-29 05:23:17 +00:00
2015-06-24 12:43:35 +00:00
WARN_LOG ( VIDEO , " Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s%s%s%s " ,
2013-02-17 20:41:00 +00:00
g_ActiveConfig . backend_info . bSupportsDualSourceBlend ? " " : " DualSourceBlend " ,
2013-03-29 13:27:33 +00:00
g_ActiveConfig . backend_info . bSupportsPrimitiveRestart ? " " : " PrimitiveRestart " ,
2013-07-22 10:02:16 +00:00
g_ActiveConfig . backend_info . bSupportsEarlyZ ? " " : " EarlyZ " ,
2013-03-25 14:14:24 +00:00
g_ogl_config . bSupportsGLPinnedMemory ? " " : " PinnedMemory " ,
g_ogl_config . bSupportsGLSLCache ? " " : " ShaderCache " ,
g_ogl_config . bSupportsGLBaseVertex ? " " : " BaseVertex " ,
2013-12-27 16:56:03 +00:00
g_ogl_config . bSupportsGLBufferStorage ? " " : " BufferStorage " ,
2013-03-25 14:14:24 +00:00
g_ogl_config . bSupportsGLSync ? " " : " Sync " ,
2014-04-30 16:48:40 +00:00
g_ogl_config . bSupportsMSAA ? " " : " MSAA " ,
2015-09-01 05:17:24 +00:00
g_ActiveConfig . backend_info . bSupportsSSAA ? " " : " SSAA " ,
2015-05-18 22:54:00 +00:00
g_ActiveConfig . backend_info . bSupportsGSInstancing ? " " : " GSInstancing " ,
2015-06-13 13:51:58 +00:00
g_ActiveConfig . backend_info . bSupportsClipControl ? " " : " ClipControl " ,
2015-07-25 10:10:52 +00:00
g_ogl_config . bSupportsCopySubImage ? " " : " CopyImageSubData "
2013-04-04 16:55:37 +00:00
) ;
2013-10-29 05:23:17 +00:00
2015-12-12 12:00:08 +00:00
s_last_multisamples = g_ActiveConfig . iMultisamples ;
s_MSAASamples = s_last_multisamples ;
2014-12-28 17:26:25 +00:00
2014-12-28 17:35:23 +00:00
s_last_stereo_mode = g_ActiveConfig . iStereoMode > 0 ;
2014-12-28 17:26:25 +00:00
s_last_xfb_mode = g_ActiveConfig . bUseRealXFB ;
2013-10-29 05:23:17 +00:00
2013-04-19 13:21:45 +00:00
// Decide framebuffer size
2012-12-17 20:54:20 +00:00
s_backbuffer_width = ( int ) GLInterface - > GetBackBufferWidth ( ) ;
s_backbuffer_height = ( int ) GLInterface - > GetBackBufferHeight ( ) ;
2010-09-28 02:15:02 +00:00
2009-03-05 23:11:13 +00:00
// Handle VSync on/off
2013-03-30 21:17:39 +00:00
s_vsync = g_ActiveConfig . IsVSync ( ) ;
2015-09-18 18:12:20 +00:00
if ( ! DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENVSYNC ) )
GLInterface - > SwapInterval ( s_vsync ) ;
2009-02-23 07:23:34 +00:00
2012-09-28 21:48:18 +00:00
// TODO: Move these somewhere else?
FramebufferManagerBase : : SetLastXfbWidth ( MAX_XFB_WIDTH ) ;
FramebufferManagerBase : : SetLastXfbHeight ( MAX_XFB_HEIGHT ) ;
2010-05-19 03:15:36 +00:00
2012-09-28 22:04:55 +00:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height ) ;
2010-08-10 01:08:22 +00:00
2014-12-28 17:35:23 +00:00
s_last_efb_scale = g_ActiveConfig . iEFBScale ;
2012-09-28 22:19:28 +00:00
CalculateTargetSize ( s_backbuffer_width , s_backbuffer_height ) ;
2010-09-30 15:24:34 +00:00
2015-01-02 17:06:56 +00:00
PixelShaderManager : : SetEfbScaleChanged ( ) ;
2010-08-10 01:08:22 +00:00
// Because of the fixed framebuffer size we need to disable the resolution
// options while running
2009-10-22 20:22:50 +00:00
g_Config . bRunning = true ;
2013-10-29 05:23:17 +00:00
2010-06-05 01:38:22 +00:00
glStencilFunc ( GL_ALWAYS , 0 , 0 ) ;
glBlendFunc ( GL_ONE , GL_ONE ) ;
glViewport ( 0 , 0 , GetTargetWidth ( ) , GetTargetHeight ( ) ) ; // Reset The Current Viewport
2015-05-18 23:18:04 +00:00
if ( g_ActiveConfig . backend_info . bSupportsClipControl )
glClipControl ( GL_LOWER_LEFT , GL_ZERO_TO_ONE ) ;
2010-06-05 01:38:22 +00:00
2010-12-27 03:18:01 +00:00
glClearColor ( 0.0f , 0.0f , 0.0f , 1.0f ) ;
2013-05-06 04:33:49 +00:00
glClearDepthf ( 1.0f ) ;
2010-06-05 01:38:22 +00:00
glEnable ( GL_DEPTH_TEST ) ;
glDepthFunc ( GL_LEQUAL ) ;
2010-08-10 01:08:22 +00:00
2010-06-05 01:38:22 +00:00
glPixelStorei ( GL_UNPACK_ALIGNMENT , 4 ) ; // 4-byte pixel alignment
2010-08-10 01:08:22 +00:00
2010-06-05 01:38:22 +00:00
glDisable ( GL_STENCIL_TEST ) ;
glEnable ( GL_SCISSOR_TEST ) ;
glScissor ( 0 , 0 , GetTargetWidth ( ) , GetTargetHeight ( ) ) ;
2013-01-03 11:06:47 +00:00
glBlendColor ( 0 , 0 , 0 , 0.5f ) ;
2013-05-06 04:33:49 +00:00
glClearDepthf ( 1.0f ) ;
2014-03-10 11:30:55 +00:00
if ( g_ActiveConfig . backend_info . bSupportsPrimitiveRestart )
2013-04-10 10:58:52 +00:00
{
2013-12-30 13:22:50 +00:00
if ( GLInterface - > GetMode ( ) = = GLInterfaceMode : : MODE_OPENGLES3 )
2014-08-15 18:09:53 +00:00
{
2013-12-30 13:22:50 +00:00
glEnable ( GL_PRIMITIVE_RESTART_FIXED_INDEX ) ;
2014-08-15 18:09:53 +00:00
}
2013-04-10 10:58:52 +00:00
else
2014-08-15 18:09:53 +00:00
{
2015-12-13 17:39:45 +00:00
if ( GLExtensions : : Version ( ) > = 310 )
2013-12-30 13:22:50 +00:00
{
glEnable ( GL_PRIMITIVE_RESTART ) ;
glPrimitiveRestartIndex ( 65535 ) ;
}
else
{
glEnableClientState ( GL_PRIMITIVE_RESTART_NV ) ;
glPrimitiveRestartIndexNV ( 65535 ) ;
}
2014-08-15 18:09:53 +00:00
}
2013-09-16 15:43:57 +00:00
}
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ( ) ;
2014-06-05 08:12:05 +00:00
ClearEFBCache ( ) ;
2009-02-23 07:23:34 +00:00
}
2010-11-18 02:21:26 +00:00
Renderer : : ~ Renderer ( )
2013-01-25 19:39:19 +00:00
{
}
void Renderer : : Shutdown ( )
2010-06-05 01:38:22 +00:00
{
2015-12-22 23:47:20 +00:00
g_framebuffer_manager . reset ( ) ;
2013-10-29 05:23:17 +00:00
2009-09-06 15:11:21 +00:00
g_Config . bRunning = false ;
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ( ) ;
2013-10-29 05:23:17 +00:00
2015-12-22 23:47:20 +00:00
s_raster_font . reset ( ) ;
m_post_processor . reset ( ) ;
2014-12-04 07:24:58 +00:00
OpenGL_DeleteAttributelessVAO ( ) ;
2013-01-25 19:39:19 +00:00
}
2009-09-03 19:24:16 +00:00
2013-01-25 19:39:19 +00:00
void Renderer : : Init ( )
{
2013-07-22 13:41:10 +00:00
// Initialize the FramebufferManager
2015-12-22 23:47:20 +00:00
g_framebuffer_manager = std : : make_unique < FramebufferManager > ( s_target_width , s_target_height ,
2014-04-30 16:13:31 +00:00
s_MSAASamples ) ;
2013-10-29 05:23:17 +00:00
2015-12-22 23:47:20 +00:00
m_post_processor = std : : make_unique < OpenGLPostProcessing > ( ) ;
s_raster_font = std : : make_unique < RasterFont > ( ) ;
2013-10-29 05:23:17 +00:00
2014-12-11 09:00:37 +00:00
OpenGL_CreateAttributelessVAO ( ) ;
2010-09-28 02:15:02 +00:00
}
2014-03-12 19:33:41 +00:00
void Renderer : : RenderText ( const std : : string & text , int left , int top , u32 color )
2010-09-28 02:15:02 +00:00
{
2012-12-17 20:54:20 +00:00
const int nBackbufferWidth = ( int ) GLInterface - > GetBackBufferWidth ( ) ;
const int nBackbufferHeight = ( int ) GLInterface - > GetBackBufferHeight ( ) ;
2011-11-30 03:50:31 +00:00
2015-12-22 23:47:20 +00:00
s_raster_font - > printMultilineText ( text ,
2010-09-28 02:15:02 +00:00
left * 2.0f / ( float ) nBackbufferWidth - 1 ,
1 - top * 2.0f / ( float ) nBackbufferHeight ,
2012-12-11 11:37:08 +00:00
0 , nBackbufferWidth , nBackbufferHeight , color ) ;
2010-09-28 02:15:02 +00:00
}
TargetRectangle Renderer : : ConvertEFBRectangle ( const EFBRectangle & rc )
{
2010-09-30 15:24:34 +00:00
TargetRectangle result ;
2011-05-12 02:14:45 +00:00
result . left = EFBToScaledX ( rc . left ) ;
result . top = EFBToScaledY ( EFB_HEIGHT - rc . top ) ;
result . right = EFBToScaledX ( rc . right ) ;
result . bottom = EFBToScaledY ( EFB_HEIGHT - rc . bottom ) ;
2010-09-30 15:24:34 +00:00
return result ;
2010-09-28 02:15:02 +00:00
}
2009-06-07 12:06:15 +00:00
// Function: This function handles the OpenGL glScissor() function
2009-09-08 16:07:13 +00:00
// ----------------------------
2009-02-23 07:23:34 +00:00
// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
// case 0x52 > SetScissorRect()
2009-09-08 16:07:13 +00:00
// ----------------------------
2009-06-22 09:31:30 +00:00
// bpmem.scissorTL.x, y = 342x342
// bpmem.scissorBR.x, y = 981x821
2009-02-23 07:23:34 +00:00
// Renderer::GetTargetHeight() = the fixed ini file setting
// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box
// therefore the width and height are (scissorBR + 1) - scissorTL
2014-02-04 20:17:38 +00:00
void Renderer : : SetScissorRect ( const EFBRectangle & rc )
2009-02-23 07:23:34 +00:00
{
2014-02-04 20:17:38 +00:00
TargetRectangle trc = g_renderer - > ConvertEFBRectangle ( rc ) ;
glScissor ( trc . left , trc . bottom , trc . GetWidth ( ) , trc . GetHeight ( ) ) ;
2009-02-23 07:23:34 +00:00
}
2010-09-28 02:15:02 +00:00
void Renderer : : SetColorMask ( )
{
2010-12-20 16:57:29 +00:00
// Only enable alpha channel if it's supported by the current EFB format
2010-12-21 22:18:40 +00:00
GLenum ColorMask = GL_FALSE , AlphaMask = GL_FALSE ;
2013-01-08 16:23:01 +00:00
if ( bpmem . alpha_test . TestResult ( ) ! = AlphaTest : : FAIL )
{
if ( bpmem . blendmode . colorupdate )
ColorMask = GL_TRUE ;
2014-03-23 20:44:23 +00:00
if ( bpmem . blendmode . alphaupdate & & ( bpmem . zcontrol . pixel_format = = PEControl : : RGBA6_Z24 ) )
2013-01-08 16:23:01 +00:00
AlphaMask = GL_TRUE ;
}
2010-09-28 02:15:02 +00:00
glColorMask ( ColorMask , ColorMask , ColorMask , AlphaMask ) ;
}
2011-08-22 04:15:02 +00:00
void ClearEFBCache ( )
{
2014-06-05 08:12:05 +00:00
if ( ! s_efbCacheIsCleared )
{
s_efbCacheIsCleared = true ;
memset ( s_efbCacheValid , 0 , sizeof ( s_efbCacheValid ) ) ;
}
2011-08-22 04:15:02 +00:00
}
2015-06-06 18:09:22 +00:00
void Renderer : : UpdateEFBCache ( EFBAccessType type , u32 cacheRectIdx , const EFBRectangle & efbPixelRc , const TargetRectangle & targetPixelRc , const void * data )
2011-08-22 04:15:02 +00:00
{
u32 cacheType = ( type = = PEEK_Z ? 0 : 1 ) ;
if ( ! s_efbCache [ cacheType ] [ cacheRectIdx ] . size ( ) )
s_efbCache [ cacheType ] [ cacheRectIdx ] . resize ( EFB_CACHE_RECT_SIZE * EFB_CACHE_RECT_SIZE ) ;
u32 targetPixelRcWidth = targetPixelRc . right - targetPixelRc . left ;
2012-07-23 17:56:57 +00:00
u32 efbPixelRcHeight = efbPixelRc . bottom - efbPixelRc . top ;
u32 efbPixelRcWidth = efbPixelRc . right - efbPixelRc . left ;
2011-08-22 04:15:02 +00:00
2012-07-23 17:56:57 +00:00
for ( u32 yCache = 0 ; yCache < efbPixelRcHeight ; + + yCache )
2011-08-22 04:15:02 +00:00
{
u32 yEFB = efbPixelRc . top + yCache ;
u32 yPixel = ( EFBToScaledY ( EFB_HEIGHT - yEFB ) + EFBToScaledY ( EFB_HEIGHT - yEFB - 1 ) ) / 2 ;
u32 yData = yPixel - targetPixelRc . bottom ;
2012-07-23 17:56:57 +00:00
for ( u32 xCache = 0 ; xCache < efbPixelRcWidth ; + + xCache )
2011-08-22 04:15:02 +00:00
{
u32 xEFB = efbPixelRc . left + xCache ;
u32 xPixel = ( EFBToScaledX ( xEFB ) + EFBToScaledX ( xEFB + 1 ) ) / 2 ;
u32 xData = xPixel - targetPixelRc . left ;
2015-06-06 18:09:22 +00:00
u32 value ;
if ( type = = PEEK_Z )
{
float * ptr = ( float * ) data ;
value = MathUtil : : Clamp < u32 > ( ( u32 ) ( ptr [ yData * targetPixelRcWidth + xData ] * 16777216.0f ) , 0 , 0xFFFFFF ) ;
}
else
{
u32 * ptr = ( u32 * ) data ;
value = ptr [ yData * targetPixelRcWidth + xData ] ;
}
s_efbCache [ cacheType ] [ cacheRectIdx ] [ yCache * EFB_CACHE_RECT_SIZE + xCache ] = value ;
2011-08-22 04:15:02 +00:00
}
}
s_efbCacheValid [ cacheType ] [ cacheRectIdx ] = true ;
2014-06-05 08:12:05 +00:00
s_efbCacheIsCleared = false ;
2011-08-22 04:15:02 +00:00
}
2010-10-24 19:52:52 +00:00
// This function allows the CPU to directly access the EFB.
// There are EFB peeks (which will read the color or depth of a pixel)
// and EFB pokes (which will change the color or depth of a pixel).
//
// The behavior of EFB peeks can only be modified by:
2014-02-17 04:51:41 +00:00
// - GX_PokeAlphaRead
2010-10-24 19:52:52 +00:00
// The behavior of EFB pokes can be modified by:
2014-02-17 04:51:41 +00:00
// - GX_PokeAlphaMode (TODO)
// - GX_PokeAlphaUpdate (TODO)
// - GX_PokeBlendMode (TODO)
// - GX_PokeColorUpdate (TODO)
// - GX_PokeDither (TODO)
// - GX_PokeDstAlpha (TODO)
// - GX_PokeZMode (TODO)
2010-10-22 19:40:05 +00:00
u32 Renderer : : AccessEFB ( EFBAccessType type , u32 x , u32 y , u32 poke_data )
2010-09-28 02:15:02 +00:00
{
2011-12-01 01:40:58 +00:00
u32 cacheRectIdx = ( y / EFB_CACHE_RECT_SIZE ) * EFB_CACHE_WIDTH
+ ( x / EFB_CACHE_RECT_SIZE ) ;
2011-08-22 04:15:02 +00:00
2010-09-28 02:15:02 +00:00
EFBRectangle efbPixelRc ;
2014-12-12 15:11:17 +00:00
if ( type = = PEEK_COLOR | | type = = PEEK_Z )
{
// Get the rectangular target region containing the EFB pixel
efbPixelRc . left = ( x / EFB_CACHE_RECT_SIZE ) * EFB_CACHE_RECT_SIZE ;
efbPixelRc . top = ( y / EFB_CACHE_RECT_SIZE ) * EFB_CACHE_RECT_SIZE ;
efbPixelRc . right = std : : min ( efbPixelRc . left + EFB_CACHE_RECT_SIZE , ( u32 ) EFB_WIDTH ) ;
efbPixelRc . bottom = std : : min ( efbPixelRc . top + EFB_CACHE_RECT_SIZE , ( u32 ) EFB_HEIGHT ) ;
}
else
{
efbPixelRc . left = x ;
efbPixelRc . top = y ;
efbPixelRc . right = x + 1 ;
efbPixelRc . bottom = y + 1 ;
}
2010-09-28 02:15:02 +00:00
2010-09-30 15:24:34 +00:00
TargetRectangle targetPixelRc = ConvertEFBRectangle ( efbPixelRc ) ;
2011-08-22 04:15:02 +00:00
u32 targetPixelRcWidth = targetPixelRc . right - targetPixelRc . left ;
u32 targetPixelRcHeight = targetPixelRc . top - targetPixelRc . bottom ;
2010-09-28 02:15:02 +00:00
// TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
switch ( type )
{
case PEEK_Z :
{
2011-08-22 04:15:02 +00:00
if ( ! s_efbCacheValid [ 0 ] [ cacheRectIdx ] )
2010-09-28 02:15:02 +00:00
{
2011-08-22 04:15:02 +00:00
if ( s_MSAASamples > 1 )
{
2013-08-26 20:18:00 +00:00
g_renderer - > ResetAPIState ( ) ;
2013-10-29 05:23:17 +00:00
2011-08-22 04:15:02 +00:00
// Resolve our rectangle.
FramebufferManager : : GetEFBDepthTexture ( efbPixelRc ) ;
2013-01-03 11:06:47 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , FramebufferManager : : GetResolvedFramebuffer ( ) ) ;
2013-10-29 05:23:17 +00:00
2013-08-26 20:18:00 +00:00
g_renderer - > RestoreAPIState ( ) ;
2011-08-22 04:15:02 +00:00
}
2010-09-28 02:15:02 +00:00
2016-01-03 20:12:46 +00:00
std : : unique_ptr < float [ ] > depthMap ( new float [ targetPixelRcWidth * targetPixelRcHeight ] ) ;
2010-09-28 02:15:02 +00:00
2011-08-22 04:15:02 +00:00
glReadPixels ( targetPixelRc . left , targetPixelRc . bottom , targetPixelRcWidth , targetPixelRcHeight ,
2015-06-06 18:09:22 +00:00
GL_DEPTH_COMPONENT , GL_FLOAT , depthMap . get ( ) ) ;
2011-08-22 04:15:02 +00:00
2015-05-08 13:28:29 +00:00
UpdateEFBCache ( type , cacheRectIdx , efbPixelRc , targetPixelRc , depthMap . get ( ) ) ;
2011-08-22 04:15:02 +00:00
}
u32 xRect = x % EFB_CACHE_RECT_SIZE ;
u32 yRect = y % EFB_CACHE_RECT_SIZE ;
2015-05-08 13:29:36 +00:00
u32 z = s_efbCache [ 0 ] [ cacheRectIdx ] [ yRect * EFB_CACHE_RECT_SIZE + xRect ] ;
2010-09-28 02:15:02 +00:00
2015-06-06 18:09:22 +00:00
// if Z is in 16 bit format you must return a 16 bit integer
2014-03-23 20:44:23 +00:00
if ( bpmem . zcontrol . pixel_format = = PEControl : : RGB565_Z16 )
2015-06-06 18:07:49 +00:00
z = z > > 8 ;
2015-06-06 18:09:22 +00:00
2015-06-06 18:07:49 +00:00
return z ;
2010-09-28 02:15:02 +00:00
}
case PEEK_COLOR : // GXPeekARGB
{
// Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
// Tested in Killer 7, the first 8bits represent the alpha value which is used to
// determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
// Wind Waker is also using it for the pictograph to determine the color of each pixel
2011-08-22 04:15:02 +00:00
if ( ! s_efbCacheValid [ 1 ] [ cacheRectIdx ] )
2010-09-28 02:15:02 +00:00
{
2011-08-22 04:15:02 +00:00
if ( s_MSAASamples > 1 )
{
2013-08-26 20:18:00 +00:00
g_renderer - > ResetAPIState ( ) ;
2013-10-29 05:23:17 +00:00
2011-08-22 04:15:02 +00:00
// Resolve our rectangle.
FramebufferManager : : GetEFBColorTexture ( efbPixelRc ) ;
2013-01-03 11:06:47 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , FramebufferManager : : GetResolvedFramebuffer ( ) ) ;
2013-10-29 05:23:17 +00:00
2013-08-26 20:18:00 +00:00
g_renderer - > RestoreAPIState ( ) ;
2011-08-22 04:15:02 +00:00
}
2016-01-03 20:12:46 +00:00
std : : unique_ptr < u32 [ ] > colorMap ( new u32 [ targetPixelRcWidth * targetPixelRcHeight ] ) ;
2011-08-22 04:15:02 +00:00
2013-12-30 13:22:50 +00:00
if ( GLInterface - > GetMode ( ) = = GLInterfaceMode : : MODE_OPENGLES3 )
2013-05-06 04:33:49 +00:00
// XXX: Swap colours
2013-12-30 13:22:50 +00:00
glReadPixels ( targetPixelRc . left , targetPixelRc . bottom , targetPixelRcWidth , targetPixelRcHeight ,
2015-05-08 13:28:29 +00:00
GL_RGBA , GL_UNSIGNED_BYTE , colorMap . get ( ) ) ;
2013-12-30 13:22:50 +00:00
else
glReadPixels ( targetPixelRc . left , targetPixelRc . bottom , targetPixelRcWidth , targetPixelRcHeight ,
2015-05-08 13:28:29 +00:00
GL_BGRA , GL_UNSIGNED_INT_8_8_8_8_REV , colorMap . get ( ) ) ;
2010-09-28 02:15:02 +00:00
2015-05-08 13:28:29 +00:00
UpdateEFBCache ( type , cacheRectIdx , efbPixelRc , targetPixelRc , colorMap . get ( ) ) ;
2011-08-22 04:15:02 +00:00
}
u32 xRect = x % EFB_CACHE_RECT_SIZE ;
u32 yRect = y % EFB_CACHE_RECT_SIZE ;
2015-05-08 13:29:36 +00:00
u32 color = s_efbCache [ 1 ] [ cacheRectIdx ] [ yRect * EFB_CACHE_RECT_SIZE + xRect ] ;
2010-09-28 02:15:02 +00:00
2010-10-24 19:52:52 +00:00
// check what to do with the alpha channel (GX_PokeAlphaRead)
2014-02-15 02:23:35 +00:00
PixelEngine : : UPEAlphaReadReg alpha_read_mode = PixelEngine : : GetAlphaReadMode ( ) ;
2010-12-27 03:18:01 +00:00
2014-03-23 20:44:23 +00:00
if ( bpmem . zcontrol . pixel_format = = PEControl : : RGBA6_Z24 )
2010-12-27 03:18:01 +00:00
{
color = RGBA8ToRGBA6ToRGBA8 ( color ) ;
}
2014-03-23 20:44:23 +00:00
else if ( bpmem . zcontrol . pixel_format = = PEControl : : RGB565_Z16 )
2010-12-27 03:18:01 +00:00
{
2010-12-27 18:09:03 +00:00
color = RGBA8ToRGB565ToRGBA8 ( color ) ;
}
2014-03-23 20:44:23 +00:00
if ( bpmem . zcontrol . pixel_format ! = PEControl : : RGBA6_Z24 )
2010-12-27 03:18:01 +00:00
{
color | = 0xFF000000 ;
}
2014-08-15 18:09:53 +00:00
if ( alpha_read_mode . ReadMode = = 2 )
{
// GX_READ_NONE
return color ;
}
else if ( alpha_read_mode . ReadMode = = 1 )
{
// GX_READ_FF
return ( color | 0xFF000000 ) ;
}
else /*if(alpha_read_mode.ReadMode == 0)*/
{
// GX_READ_00
return ( color & 0x00FFFFFF ) ;
}
2010-09-28 02:15:02 +00:00
}
default :
break ;
}
return 0 ;
}
2015-12-19 14:34:56 +00:00
void Renderer : : PokeEFB ( EFBAccessType type , const EfbPokeData * points , size_t num_points )
2015-05-01 15:47:52 +00:00
{
2015-12-19 14:34:56 +00:00
FramebufferManager : : PokeEFB ( type , points , num_points ) ;
2015-05-01 15:47:52 +00:00
}
2014-11-13 22:26:49 +00:00
u16 Renderer : : BBoxRead ( int index )
{
int swapped_index = index ;
if ( index > = 2 )
swapped_index ^ = 1 ; // swap 2 and 3 for top/bottom
// Here we get the min/max value of the truncated position of the upscaled and swapped framebuffer.
// So we have to correct them to the unscaled EFB sizes.
int value = BoundingBox : : Get ( swapped_index ) ;
if ( index < 2 )
{
// left/right
value = value * EFB_WIDTH / s_target_width ;
}
else
{
// up/down -- we have to swap up and down
value = value * EFB_HEIGHT / s_target_height ;
value = EFB_HEIGHT - value - 1 ;
}
if ( index & 1 )
value + + ; // fix max values to describe the outer border
return value ;
}
void Renderer : : BBoxWrite ( int index , u16 _value )
{
int value = _value ; // u16 isn't enough to multiply by the efb width
if ( index & 1 )
value - - ;
if ( index < 2 )
{
value = value * s_target_width / EFB_WIDTH ;
}
else
{
index ^ = 1 ; // swap 2 and 3 for top/bottom
value = EFB_HEIGHT - value - 1 ;
value = value * s_target_height / EFB_HEIGHT ;
}
BoundingBox : : Set ( index , value ) ;
}
2014-02-04 09:45:38 +00:00
void Renderer : : SetViewport ( )
2010-09-28 02:15:02 +00:00
{
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
// [0] = width/2
// [1] = height/2
// [2] = 16777215 * (farz - nearz)
// [3] = xorig + width/2 + 342
// [4] = yorig + height/2 + 342
// [5] = 16777215 * farz
2010-09-30 15:24:34 +00:00
2011-05-12 02:14:45 +00:00
int scissorXOff = bpmem . scissorOffset . x * 2 ;
int scissorYOff = bpmem . scissorOffset . y * 2 ;
2010-09-30 15:24:34 +00:00
2010-12-10 15:54:14 +00:00
// TODO: ceil, floor or just cast to int?
2014-04-27 18:59:04 +00:00
float X = EFBToScaledXf ( xfmem . viewport . xOrig - xfmem . viewport . wd - ( float ) scissorXOff ) ;
float Y = EFBToScaledYf ( ( float ) EFB_HEIGHT - xfmem . viewport . yOrig + xfmem . viewport . ht + ( float ) scissorYOff ) ;
float Width = EFBToScaledXf ( 2.0f * xfmem . viewport . wd ) ;
float Height = EFBToScaledYf ( - 2.0f * xfmem . viewport . ht ) ;
2016-01-03 14:39:34 +00:00
float GLNear = MathUtil : : Clamp < float > ( xfmem . viewport . farZ - MathUtil : : Clamp < float > ( xfmem . viewport . zRange , - 16777216.0f , 16777216.0f ) , 0.0f , 16777215.0f ) / 16777216.0f ;
2015-05-16 19:25:52 +00:00
float GLFar = MathUtil : : Clamp < float > ( xfmem . viewport . farZ , 0.0f , 16777215.0f ) / 16777216.0f ;
2010-09-30 15:24:34 +00:00
if ( Width < 0 )
2010-09-28 02:15:02 +00:00
{
2010-09-30 15:24:34 +00:00
X + = Width ;
2010-12-10 15:54:14 +00:00
Width * = - 1 ;
2010-09-28 02:15:02 +00:00
}
2010-09-30 15:24:34 +00:00
if ( Height < 0 )
2010-09-28 02:15:02 +00:00
{
2010-09-30 15:24:34 +00:00
Y + = Height ;
Height * = - 1 ;
2010-09-28 02:15:02 +00:00
}
2011-05-12 02:14:45 +00:00
2010-09-28 02:15:02 +00:00
// Update the view port
2014-03-10 11:30:55 +00:00
if ( g_ogl_config . bSupportViewportFloat )
2013-10-29 14:29:06 +00:00
{
glViewportIndexedf ( 0 , X , Y , Width , Height ) ;
}
else
{
2014-08-20 03:18:02 +00:00
auto iceilf = [ ] ( float f )
{
return static_cast < GLint > ( ceilf ( f ) ) ;
} ;
glViewport ( iceilf ( X ) , iceilf ( Y ) , iceilf ( Width ) , iceilf ( Height ) ) ;
2013-10-29 14:29:06 +00:00
}
2015-05-22 20:42:25 +00:00
glDepthRangef ( GLFar , GLNear ) ;
2010-09-28 02:15:02 +00:00
}
2010-12-19 22:00:25 +00:00
void Renderer : : ClearScreen ( const EFBRectangle & rc , bool colorEnable , bool alphaEnable , bool zEnable , u32 color , u32 z )
2009-07-15 00:51:24 +00:00
{
2010-12-28 16:16:27 +00:00
ResetAPIState ( ) ;
2009-07-15 00:51:24 +00:00
2011-11-30 03:50:31 +00:00
// color
GLboolean const
color_mask = colorEnable ? GL_TRUE : GL_FALSE ,
alpha_mask = alphaEnable ? GL_TRUE : GL_FALSE ;
glColorMask ( color_mask , color_mask , color_mask , alpha_mask ) ;
2009-07-15 00:51:24 +00:00
2011-11-30 03:50:31 +00:00
glClearColor (
float ( ( color > > 16 ) & 0xFF ) / 255.0f ,
float ( ( color > > 8 ) & 0xFF ) / 255.0f ,
float ( ( color > > 0 ) & 0xFF ) / 255.0f ,
float ( ( color > > 24 ) & 0xFF ) / 255.0f ) ;
// depth
glDepthMask ( zEnable ? GL_TRUE : GL_FALSE ) ;
2009-07-15 00:51:24 +00:00
2015-05-07 21:29:16 +00:00
glClearDepthf ( float ( z & 0xFFFFFF ) / 16777216.0f ) ;
2011-11-30 03:50:31 +00:00
// Update rect for clearing the picture
glEnable ( GL_SCISSOR_TEST ) ;
TargetRectangle const targetRc = ConvertEFBRectangle ( rc ) ;
glScissor ( targetRc . left , targetRc . bottom , targetRc . GetWidth ( ) , targetRc . GetHeight ( ) ) ;
2009-07-15 00:51:24 +00:00
2011-11-30 03:50:31 +00:00
// glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
2010-12-28 16:16:27 +00:00
RestoreAPIState ( ) ;
2011-08-22 04:15:02 +00:00
ClearEFBCache ( ) ;
2009-07-15 00:51:24 +00:00
}
2010-08-10 01:08:22 +00:00
2014-12-20 16:10:58 +00:00
void Renderer : : BlitScreen ( TargetRectangle src , TargetRectangle dst , GLuint src_texture , int src_width , int src_height )
{
if ( g_ActiveConfig . iStereoMode = = STEREO_SBS | | g_ActiveConfig . iStereoMode = = STEREO_TAB )
{
TargetRectangle leftRc , rightRc ;
2015-09-10 20:22:26 +00:00
// Top-and-Bottom mode needs to compensate for inverted vertical screen coordinates.
if ( g_ActiveConfig . iStereoMode = = STEREO_TAB )
ConvertStereoRectangle ( dst , rightRc , leftRc ) ;
else
ConvertStereoRectangle ( dst , leftRc , rightRc ) ;
2014-12-20 16:10:58 +00:00
m_post_processor - > BlitFromTexture ( src , leftRc , src_texture , src_width , src_height , 0 ) ;
m_post_processor - > BlitFromTexture ( src , rightRc , src_texture , src_width , src_height , 1 ) ;
}
else
{
m_post_processor - > BlitFromTexture ( src , dst , src_texture , src_width , src_height ) ;
}
}
2010-12-27 21:56:20 +00:00
void Renderer : : ReinterpretPixelData ( unsigned int convtype )
{
2013-07-22 13:41:10 +00:00
if ( convtype = = 0 | | convtype = = 2 )
{
FramebufferManager : : ReinterpretPixelData ( convtype ) ;
}
else
{
ERROR_LOG ( VIDEO , " Trying to reinterpret pixel data with unsupported conversion type %d " , convtype ) ;
}
2010-12-27 21:56:20 +00:00
}
2010-09-28 02:15:02 +00:00
void Renderer : : SetBlendMode ( bool forceUpdate )
2009-06-26 08:57:53 +00:00
{
2013-01-13 22:35:07 +00:00
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
2014-03-23 20:44:23 +00:00
bool target_has_alpha = bpmem . zcontrol . pixel_format = = PEControl : : RGBA6_Z24 ;
2013-10-29 05:23:17 +00:00
2015-09-09 19:20:46 +00:00
bool useDstAlpha = bpmem . dstalpha . enable & & bpmem . blendmode . alphaupdate & & target_has_alpha ;
2013-03-16 23:36:13 +00:00
bool useDualSource = useDstAlpha & & g_ActiveConfig . backend_info . bSupportsDualSourceBlend ;
2013-10-29 05:23:17 +00:00
2013-01-13 22:35:07 +00:00
const GLenum glSrcFactors [ 8 ] =
{
GL_ZERO ,
GL_ONE ,
GL_DST_COLOR ,
GL_ONE_MINUS_DST_COLOR ,
2013-03-28 21:32:59 +00:00
( useDualSource ) ? GL_SRC1_ALPHA : ( GLenum ) GL_SRC_ALPHA ,
( useDualSource ) ? GL_ONE_MINUS_SRC1_ALPHA : ( GLenum ) GL_ONE_MINUS_SRC_ALPHA ,
2013-01-13 22:35:07 +00:00
( target_has_alpha ) ? GL_DST_ALPHA : ( GLenum ) GL_ONE ,
( target_has_alpha ) ? GL_ONE_MINUS_DST_ALPHA : ( GLenum ) GL_ZERO
} ;
const GLenum glDestFactors [ 8 ] =
{
GL_ZERO ,
GL_ONE ,
GL_SRC_COLOR ,
GL_ONE_MINUS_SRC_COLOR ,
2013-03-28 21:32:59 +00:00
( useDualSource ) ? GL_SRC1_ALPHA : ( GLenum ) GL_SRC_ALPHA ,
( useDualSource ) ? GL_ONE_MINUS_SRC1_ALPHA : ( GLenum ) GL_ONE_MINUS_SRC_ALPHA ,
2013-01-13 22:35:07 +00:00
( target_has_alpha ) ? GL_DST_ALPHA : ( GLenum ) GL_ONE ,
( target_has_alpha ) ? GL_ONE_MINUS_DST_ALPHA : ( GLenum ) GL_ZERO
} ;
2010-09-28 02:15:02 +00:00
// blend mode bit mask
// 0 - blend enable
2013-01-17 23:44:35 +00:00
// 1 - dst alpha enabled
2010-09-28 02:15:02 +00:00
// 2 - reverse subtract enable (else add)
// 3-5 - srcRGB function
// 6-8 - dstRGB function
2013-01-17 23:44:35 +00:00
u32 newval = useDualSource < < 1 ;
newval | = bpmem . blendmode . subtract < < 2 ;
2010-09-28 02:15:02 +00:00
if ( bpmem . blendmode . subtract )
2014-08-15 18:09:53 +00:00
{
2010-09-28 02:15:02 +00:00
newval | = 0x0049 ; // enable blending src 1 dst 1
2014-08-15 18:09:53 +00:00
}
2010-09-28 02:15:02 +00:00
else if ( bpmem . blendmode . blendenable )
2010-07-02 17:09:53 +00:00
{
2010-09-28 02:15:02 +00:00
newval | = 1 ; // enable blending
newval | = bpmem . blendmode . srcfactor < < 3 ;
newval | = bpmem . blendmode . dstfactor < < 6 ;
2009-08-31 17:47:17 +00:00
}
2010-09-28 02:15:02 +00:00
u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode ;
if ( changes & 1 )
2014-08-15 18:09:53 +00:00
{
2010-09-28 02:15:02 +00:00
// blend enable change
( newval & 1 ) ? glEnable ( GL_BLEND ) : glDisable ( GL_BLEND ) ;
2014-08-15 18:09:53 +00:00
}
2010-09-28 02:15:02 +00:00
if ( changes & 4 )
2010-10-23 19:55:19 +00:00
{
2010-09-28 02:15:02 +00:00
// subtract enable change
2010-10-23 19:55:19 +00:00
GLenum equation = newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD ;
GLenum equationAlpha = useDualSource ? GL_FUNC_ADD : equation ;
2013-10-29 05:23:17 +00:00
2010-10-23 19:55:19 +00:00
glBlendEquationSeparate ( equation , equationAlpha ) ;
}
2010-09-28 02:15:02 +00:00
2013-01-17 23:44:35 +00:00
if ( changes & 0x1FA )
2010-10-23 19:55:19 +00:00
{
2013-03-28 21:04:33 +00:00
u32 srcidx = ( newval > > 3 ) & 7 ;
u32 dstidx = ( newval > > 6 ) & 7 ;
GLenum srcFactor = glSrcFactors [ srcidx ] ;
GLenum dstFactor = glDestFactors [ dstidx ] ;
2013-03-28 21:59:42 +00:00
// adjust alpha factors
2010-10-23 19:55:19 +00:00
if ( useDualSource )
{
2014-03-24 19:21:34 +00:00
srcidx = BlendMode : : ONE ;
dstidx = BlendMode : : ZERO ;
2013-10-29 05:23:17 +00:00
}
2013-03-28 21:04:33 +00:00
else
{
// we can't use GL_DST_COLOR or GL_ONE_MINUS_DST_COLOR for source in alpha channel so use their alpha equivalent instead
2014-08-15 18:09:53 +00:00
if ( srcidx = = BlendMode : : DSTCLR )
srcidx = BlendMode : : DSTALPHA ;
else if ( srcidx = = BlendMode : : INVDSTCLR )
srcidx = BlendMode : : INVDSTALPHA ;
2013-03-28 21:59:42 +00:00
2013-03-28 21:04:33 +00:00
// we can't use GL_SRC_COLOR or GL_ONE_MINUS_SRC_COLOR for destination in alpha channel so use their alpha equivalent instead
2014-08-15 18:09:53 +00:00
if ( dstidx = = BlendMode : : SRCCLR )
dstidx = BlendMode : : SRCALPHA ;
else if ( dstidx = = BlendMode : : INVSRCCLR )
dstidx = BlendMode : : INVSRCALPHA ;
2013-10-29 05:23:17 +00:00
}
2013-03-28 21:04:33 +00:00
GLenum srcFactorAlpha = glSrcFactors [ srcidx ] ;
GLenum dstFactorAlpha = glDestFactors [ dstidx ] ;
2010-09-28 02:15:02 +00:00
// blend RGB change
2010-10-23 19:55:19 +00:00
glBlendFuncSeparate ( srcFactor , dstFactor , srcFactorAlpha , dstFactorAlpha ) ;
}
2010-09-28 02:15:02 +00:00
s_blendMode = newval ;
2009-06-26 08:57:53 +00:00
}
2014-07-08 12:29:26 +00:00
static void DumpFrame ( const std : : vector < u8 > & data , int w , int h )
2013-02-27 01:47:48 +00:00
{
2016-01-02 18:07:08 +00:00
# if defined(HAVE_LIBAV) || defined (_WIN32)
2014-10-13 03:53:10 +00:00
if ( SConfig : : GetInstance ( ) . m_DumpFrames & & ! data . empty ( ) )
{
AVIDump : : AddFrame ( & data [ 0 ] , w , h ) ;
}
2013-02-27 01:47:48 +00:00
# endif
}
2009-06-29 07:30:48 +00:00
// This function has the final picture. We adjust the aspect ratio here.
2014-05-02 07:08:44 +00:00
void Renderer : : SwapImpl ( u32 xfbAddr , u32 fbWidth , u32 fbStride , u32 fbHeight , const EFBRectangle & rc , float Gamma )
2009-02-28 16:33:59 +00:00
{
2014-12-28 20:46:00 +00:00
if ( g_ogl_config . bSupportsDebug )
{
2015-09-10 06:27:31 +00:00
if ( LogManager : : GetInstance ( ) - > IsEnabled ( LogTypes : : HOST_GPU , LogTypes : : LERROR ) )
2014-12-28 20:46:00 +00:00
glEnable ( GL_DEBUG_OUTPUT ) ;
else
glDisable ( GL_DEBUG_OUTPUT ) ;
}
2011-02-11 18:59:42 +00:00
static int w = 0 , h = 0 ;
2016-01-12 21:44:58 +00:00
if ( Fifo : : g_bSkipCurrentFrame | | ( ! XFBWrited & & ! g_ActiveConfig . RealXFBEnabled ( ) ) | | ! fbWidth | | ! fbHeight )
2010-01-28 14:37:03 +00:00
{
2013-02-27 01:47:48 +00:00
DumpFrame ( frame_data , w , h ) ;
2011-01-31 01:28:32 +00:00
Core : : Callback_VideoCopiedToXFB ( false ) ;
2009-08-08 01:39:56 +00:00
return ;
2010-06-05 01:38:22 +00:00
}
2010-09-28 02:15:02 +00:00
2010-03-10 06:45:13 +00:00
u32 xfbCount = 0 ;
2014-10-02 06:20:46 +00:00
const XFBSourceBase * const * xfbSourceList = FramebufferManager : : GetXFBSource ( xfbAddr , fbStride , fbHeight , & xfbCount ) ;
2012-09-28 21:19:50 +00:00
if ( g_ActiveConfig . VirtualXFBEnabled ( ) & & ( ! xfbSourceList | | xfbCount = = 0 ) )
2009-06-29 07:30:48 +00:00
{
2013-02-27 01:47:48 +00:00
DumpFrame ( frame_data , w , h ) ;
2011-01-31 01:28:32 +00:00
Core : : Callback_VideoCopiedToXFB ( false ) ;
2009-06-29 07:30:48 +00:00
return ;
}
2010-06-05 01:38:22 +00:00
ResetAPIState ( ) ;
2010-11-18 02:21:26 +00:00
2012-09-28 22:04:55 +00:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height ) ;
TargetRectangle flipped_trc = GetTargetRectangle ( ) ;
2014-10-30 00:50:39 +00:00
// Flip top and bottom for some reason; TODO: Fix the code to suck less?
std : : swap ( flipped_trc . top , flipped_trc . bottom ) ;
2013-10-29 05:23:17 +00:00
2013-01-03 19:44:47 +00:00
// Copy the framebuffer to screen.
2014-10-18 07:32:24 +00:00
const XFBSource * xfbSource = nullptr ;
2010-03-10 06:45:13 +00:00
2014-03-10 11:30:55 +00:00
if ( g_ActiveConfig . bUseXFB )
2009-06-26 08:57:53 +00:00
{
2010-07-02 17:09:53 +00:00
// draw each xfb source
for ( u32 i = 0 ; i < xfbCount ; + + i )
2010-03-10 06:45:13 +00:00
{
2014-10-18 07:32:24 +00:00
xfbSource = ( const XFBSource * ) xfbSourceList [ i ] ;
2010-03-10 06:45:13 +00:00
2014-10-18 07:32:24 +00:00
TargetRectangle drawRc ;
2015-07-24 17:46:41 +00:00
TargetRectangle sourceRc ;
sourceRc . left = xfbSource - > sourceRc . left ;
sourceRc . right = xfbSource - > sourceRc . right ;
sourceRc . top = xfbSource - > sourceRc . top ;
sourceRc . bottom = xfbSource - > sourceRc . bottom ;
2010-03-10 06:45:13 +00:00
2012-09-28 21:21:09 +00:00
if ( g_ActiveConfig . bUseRealXFB )
{
2014-10-18 07:32:24 +00:00
drawRc = flipped_trc ;
2015-07-24 17:46:41 +00:00
sourceRc . right - = fbStride - fbWidth ;
2012-09-28 21:21:09 +00:00
}
else
2010-03-10 06:45:13 +00:00
{
2010-07-02 17:09:53 +00:00
// use virtual xfb with offset
int xfbHeight = xfbSource - > srcHeight ;
int xfbWidth = xfbSource - > srcWidth ;
2014-05-02 07:08:44 +00:00
int hOffset = ( ( s32 ) xfbSource - > srcAddr - ( s32 ) xfbAddr ) / ( ( s32 ) fbStride * 2 ) ;
2013-10-29 05:23:17 +00:00
2015-01-19 16:01:32 +00:00
drawRc . top = flipped_trc . top - hOffset * flipped_trc . GetHeight ( ) / ( s32 ) fbHeight ;
drawRc . bottom = flipped_trc . top - ( hOffset + xfbHeight ) * flipped_trc . GetHeight ( ) / ( s32 ) fbHeight ;
drawRc . left = flipped_trc . left + ( flipped_trc . GetWidth ( ) - xfbWidth * flipped_trc . GetWidth ( ) / ( s32 ) fbStride ) / 2 ;
drawRc . right = flipped_trc . left + ( flipped_trc . GetWidth ( ) + xfbWidth * flipped_trc . GetWidth ( ) / ( s32 ) fbStride ) / 2 ;
2013-10-29 05:23:17 +00:00
2010-09-30 15:24:34 +00:00
// The following code disables auto stretch. Kept for reference.
// scale draw area for a 1 to 1 pixel mapping with the draw target
2012-09-28 22:04:55 +00:00
//float vScale = (float)fbHeight / (float)flipped_trc.GetHeight();
//float hScale = (float)fbWidth / (float)flipped_trc.GetWidth();
2010-09-30 15:24:34 +00:00
//drawRc.top *= vScale;
//drawRc.bottom *= vScale;
//drawRc.left *= hScale;
//drawRc.right *= hScale;
2015-07-24 17:46:41 +00:00
sourceRc . right - = Renderer : : EFBToScaledX ( fbStride - fbWidth ) ;
2010-03-10 06:45:13 +00:00
}
2010-07-02 17:09:53 +00:00
// Tell the OSD Menu about the current internal resolution
OSDInternalW = xfbSource - > sourceRc . GetWidth ( ) ; OSDInternalH = xfbSource - > sourceRc . GetHeight ( ) ;
2010-03-10 06:45:13 +00:00
2014-12-20 16:10:58 +00:00
BlitScreen ( sourceRc , drawRc , xfbSource - > texture , xfbSource - > texWidth , xfbSource - > texHeight ) ;
2010-07-02 17:09:53 +00:00
}
}
else
{
2010-09-30 15:24:34 +00:00
TargetRectangle targetRc = ConvertEFBRectangle ( rc ) ;
2013-10-29 05:23:17 +00:00
2013-01-09 00:50:52 +00:00
// for msaa mode, we must resolve the efb content to non-msaa
2014-10-18 07:32:24 +00:00
GLuint tex = FramebufferManager : : ResolveAndGetRenderTarget ( rc ) ;
2014-12-20 16:10:58 +00:00
BlitScreen ( targetRc , flipped_trc , tex , s_target_width , s_target_height ) ;
2009-06-26 08:57:53 +00:00
}
2013-10-29 05:23:17 +00:00
2013-01-03 20:40:54 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
2010-09-30 15:24:34 +00:00
2009-06-08 00:44:48 +00:00
// Save screenshot
if ( s_bScreenshot )
2009-06-07 11:51:53 +00:00
{
2013-11-09 23:10:20 +00:00
std : : lock_guard < std : : mutex > lk ( s_criticalScreenshot ) ;
2015-06-25 01:44:38 +00:00
if ( SaveScreenshot ( s_sScreenshotName , flipped_trc ) )
OSD : : AddMessage ( " Screenshot saved to " + s_sScreenshotName ) ;
2009-06-07 11:51:53 +00:00
// Reset settings
2013-11-09 23:10:20 +00:00
s_sScreenshotName . clear ( ) ;
s_bScreenshot = false ;
2015-06-19 01:28:40 +00:00
s_screenshotCompleted . Set ( ) ;
2009-06-07 11:51:53 +00:00
}
2009-03-28 21:07:16 +00:00
// Frame dumps are handled a little differently in Windows
2013-05-06 11:43:04 +00:00
// Frame dumping disabled entirely on GLES3
2014-01-02 02:06:11 +00:00
if ( GLInterface - > GetMode ( ) = = GLInterfaceMode : : MODE_OPENGL )
2009-06-08 10:16:08 +00:00
{
2016-01-02 18:07:08 +00:00
# if defined(HAVE_LIBAV) || defined (_WIN32)
2014-10-13 03:53:10 +00:00
if ( SConfig : : GetInstance ( ) . m_DumpFrames )
2009-04-03 14:35:49 +00:00
{
2014-01-02 02:06:11 +00:00
std : : lock_guard < std : : mutex > lk ( s_criticalScreenshot ) ;
if ( frame_data . empty ( ) | | w ! = flipped_trc . GetWidth ( ) | |
h ! = flipped_trc . GetHeight ( ) )
2009-04-03 14:35:49 +00:00
{
2014-01-02 02:06:11 +00:00
w = flipped_trc . GetWidth ( ) ;
h = flipped_trc . GetHeight ( ) ;
frame_data . resize ( 3 * w * h ) ;
2009-03-28 21:07:16 +00:00
}
2014-01-02 02:06:11 +00:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
glReadPixels ( flipped_trc . left , flipped_trc . bottom , w , h , GL_BGR , GL_UNSIGNED_BYTE , & frame_data [ 0 ] ) ;
2014-10-26 08:53:22 +00:00
if ( w > 0 & & h > 0 )
2010-11-14 21:14:26 +00:00
{
2014-01-02 02:06:11 +00:00
if ( ! bLastFrameDumped )
{
2016-01-02 18:07:08 +00:00
bAVIDumping = AVIDump : : Start ( w , h ) ;
2014-01-02 02:06:11 +00:00
if ( ! bAVIDumping )
2014-08-15 18:09:53 +00:00
{
2014-01-02 02:06:11 +00:00
OSD : : AddMessage ( " AVIDump Start failed " , 2000 ) ;
2014-08-15 18:09:53 +00:00
}
2014-01-02 02:06:11 +00:00
else
{
OSD : : AddMessage ( StringFromFormat (
" Dumping Frames to \" %sframedump0.avi \" (%dx%d RGB24) " ,
2014-03-12 19:33:41 +00:00
File : : GetUserPath ( D_DUMPFRAMES_IDX ) . c_str ( ) , w , h ) , 2000 ) ;
2014-01-02 02:06:11 +00:00
}
}
if ( bAVIDumping )
{
2016-01-02 18:07:08 +00:00
FlipImageData ( & frame_data [ 0 ] , w , h ) ;
AVIDump : : AddFrame ( & frame_data [ 0 ] , w , h ) ;
2014-01-02 02:06:11 +00:00
}
2009-04-03 14:35:49 +00:00
2014-01-02 02:06:11 +00:00
bLastFrameDumped = true ;
}
else
2014-08-15 18:09:53 +00:00
{
2014-01-02 02:06:11 +00:00
NOTICE_LOG ( VIDEO , " Error reading framebuffer " ) ;
2014-08-15 18:09:53 +00:00
}
2009-03-28 21:07:16 +00:00
}
2009-06-08 10:16:08 +00:00
else
2009-04-03 14:35:49 +00:00
{
2014-01-02 02:06:11 +00:00
if ( bLastFrameDumped & & bAVIDumping )
{
std : : vector < u8 > ( ) . swap ( frame_data ) ;
w = h = 0 ;
AVIDump : : Stop ( ) ;
bAVIDumping = false ;
OSD : : AddMessage ( " Stop dumping frames " , 2000 ) ;
}
bLastFrameDumped = false ;
2015-01-26 01:35:29 +00:00
}
2013-05-06 11:43:04 +00:00
# endif
2014-01-02 02:06:11 +00:00
}
2010-09-28 02:15:02 +00:00
// Finish up the current frame, print some stats
2011-01-07 04:57:59 +00:00
2014-05-02 07:08:44 +00:00
SetWindowSize ( fbStride , fbHeight ) ;
2011-01-07 04:57:59 +00:00
2012-12-17 20:54:20 +00:00
GLInterface - > Update ( ) ; // just updates the render window position and the backbuffer size
2011-05-07 22:00:05 +00:00
2014-12-28 17:26:25 +00:00
bool xfbchanged = s_last_xfb_mode ! = g_ActiveConfig . bUseRealXFB ;
2010-09-28 02:15:02 +00:00
2014-05-02 07:08:44 +00:00
if ( FramebufferManagerBase : : LastXfbWidth ( ) ! = fbStride | | FramebufferManagerBase : : LastXfbHeight ( ) ! = fbHeight )
2010-05-19 03:15:36 +00:00
{
xfbchanged = true ;
2014-05-02 07:08:44 +00:00
unsigned int const last_w = ( fbStride < 1 | | fbStride > MAX_XFB_WIDTH ) ? MAX_XFB_WIDTH : fbStride ;
2013-01-29 22:40:15 +00:00
unsigned int const last_h = ( fbHeight < 1 | | fbHeight > MAX_XFB_HEIGHT ) ? MAX_XFB_HEIGHT : fbHeight ;
FramebufferManagerBase : : SetLastXfbWidth ( last_w ) ;
FramebufferManagerBase : : SetLastXfbHeight ( last_h ) ;
2010-05-19 03:15:36 +00:00
}
2010-09-28 02:15:02 +00:00
2010-05-19 03:15:36 +00:00
bool WindowResized = false ;
2012-12-17 20:54:20 +00:00
int W = ( int ) GLInterface - > GetBackBufferWidth ( ) ;
int H = ( int ) GLInterface - > GetBackBufferHeight ( ) ;
2014-12-28 17:35:23 +00:00
if ( W ! = s_backbuffer_width | | H ! = s_backbuffer_height | | s_last_efb_scale ! = g_ActiveConfig . iEFBScale )
2010-05-19 03:15:36 +00:00
{
WindowResized = true ;
2010-09-28 02:15:02 +00:00
s_backbuffer_width = W ;
s_backbuffer_height = H ;
2014-12-28 17:35:23 +00:00
s_last_efb_scale = g_ActiveConfig . iEFBScale ;
2010-05-19 03:15:36 +00:00
}
2015-07-21 00:12:29 +00:00
bool TargetSizeChanged = false ;
if ( CalculateTargetSize ( s_backbuffer_width , s_backbuffer_height ) )
{
TargetSizeChanged = true ;
}
2015-09-06 11:58:18 +00:00
if ( TargetSizeChanged | | xfbchanged | | WindowResized | |
2015-12-12 12:00:08 +00:00
( s_last_multisamples ! = g_ActiveConfig . iMultisamples ) | | ( s_last_stereo_mode ! = ( g_ActiveConfig . iStereoMode > 0 ) ) )
2010-06-05 01:38:22 +00:00
{
2014-12-28 17:26:25 +00:00
s_last_xfb_mode = g_ActiveConfig . bUseRealXFB ;
2012-09-28 22:04:55 +00:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height ) ;
2010-08-10 01:08:22 +00:00
2015-09-06 11:58:18 +00:00
if ( TargetSizeChanged | |
2015-12-12 12:00:08 +00:00
s_last_multisamples ! = g_ActiveConfig . iMultisamples | | s_last_stereo_mode ! = ( g_ActiveConfig . iStereoMode > 0 ) )
2010-05-19 03:15:36 +00:00
{
2015-01-03 00:35:39 +00:00
s_last_stereo_mode = g_ActiveConfig . iStereoMode > 0 ;
2015-12-12 12:00:08 +00:00
s_last_multisamples = g_ActiveConfig . iMultisamples ;
s_MSAASamples = s_last_multisamples ;
if ( s_MSAASamples > 1 & & s_MSAASamples > g_ogl_config . max_samples )
{
s_MSAASamples = g_ogl_config . max_samples ;
OSD : : AddMessage ( StringFromFormat ( " %d Anti Aliasing samples selected, but only %d supported by your GPU. " , s_last_multisamples , g_ogl_config . max_samples ) , 10000 ) ;
}
2013-10-29 05:23:17 +00:00
2015-12-23 13:29:32 +00:00
g_framebuffer_manager . reset ( ) ;
2015-12-22 23:47:20 +00:00
g_framebuffer_manager = std : : make_unique < FramebufferManager > ( s_target_width , s_target_height , s_MSAASamples ) ;
2015-01-02 17:06:56 +00:00
PixelShaderManager : : SetEfbScaleChanged ( ) ;
2010-05-19 03:15:36 +00:00
}
}
2009-06-07 12:06:15 +00:00
// ---------------------------------------------------------------------
2015-09-05 04:45:35 +00:00
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2009-06-07 12:06:15 +00:00
2015-09-05 04:45:35 +00:00
// Reset viewport for drawing text
glViewport ( 0 , 0 , GLInterface - > GetBackBufferWidth ( ) , GLInterface - > GetBackBufferHeight ( ) ) ;
2014-12-20 12:02:00 +00:00
2015-09-05 04:45:35 +00:00
DrawDebugText ( ) ;
// Do our OSD callbacks
2016-01-02 19:45:41 +00:00
OSD : : DoCallbacks ( OSD : : CallbackType : : OnFrame ) ;
2015-09-05 04:45:35 +00:00
OSD : : DrawMessages ( ) ;
2013-09-18 07:36:48 +00:00
2016-01-10 18:31:49 +00:00
if ( s_SurfaceNeedsChanged . IsSet ( ) )
{
GLInterface - > UpdateSurface ( ) ;
s_SurfaceNeedsChanged . Clear ( ) ;
s_ChangedSurface . Set ( ) ;
}
2010-06-05 01:38:22 +00:00
// Copy the rendered frame to the real window
2012-12-26 06:34:09 +00:00
GLInterface - > Swap ( ) ;
2010-08-10 01:08:22 +00:00
2009-06-08 20:07:20 +00:00
// Clear framebuffer
2015-09-05 04:45:35 +00:00
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
2009-06-07 12:06:15 +00:00
2014-03-10 11:30:55 +00:00
if ( s_vsync ! = g_ActiveConfig . IsVSync ( ) )
2013-03-30 21:17:39 +00:00
{
s_vsync = g_ActiveConfig . IsVSync ( ) ;
2015-09-18 18:12:20 +00:00
if ( ! DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENVSYNC ) )
GLInterface - > SwapInterval ( s_vsync ) ;
2013-03-30 21:17:39 +00:00
}
2013-03-19 00:41:45 +00:00
2010-01-17 17:44:09 +00:00
// Clean out old stuff from caches. It's not worth it to clean out the shader caches.
2014-05-19 16:31:38 +00:00
TextureCache : : Cleanup ( frameCount ) ;
2009-06-07 12:06:15 +00:00
// Render to the framebuffer.
2010-11-14 23:31:53 +00:00
FramebufferManager : : SetFramebuffer ( 0 ) ;
2009-06-07 12:06:15 +00:00
2010-06-05 01:38:22 +00:00
RestoreAPIState ( ) ;
2009-09-13 17:46:33 +00:00
2010-06-05 01:38:22 +00:00
g_Config . iSaveTargetId = 0 ;
2009-09-13 17:46:33 +00:00
2010-12-28 12:46:00 +00:00
UpdateActiveConfig ( ) ;
2012-05-28 09:31:37 +00:00
TextureCache : : OnConfigChanged ( g_ActiveConfig ) ;
2010-12-28 12:46:00 +00:00
2009-09-13 17:46:33 +00:00
// For testing zbuffer targets.
2010-06-05 01:38:22 +00:00
// Renderer::SetZBufferRender();
2013-11-16 02:59:59 +00:00
// SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget,
2010-11-18 02:21:26 +00:00
// GetTargetWidth(), GetTargetHeight());
2011-08-22 04:15:02 +00:00
// Invalidate EFB cache
ClearEFBCache ( ) ;
2009-09-13 17:46:33 +00:00
}
2009-06-07 12:06:15 +00:00
2010-09-28 02:15:02 +00:00
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
void Renderer : : ResetAPIState ( )
2009-02-23 07:23:34 +00:00
{
2010-09-28 02:15:02 +00:00
// Gets us to a reasonably sane state where it's possible to do things like
// image copies with textured quads, etc.
glDisable ( GL_SCISSOR_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_BLEND ) ;
2013-12-30 13:22:50 +00:00
if ( GLInterface - > GetMode ( ) = = GLInterfaceMode : : MODE_OPENGL )
glDisable ( GL_COLOR_LOGIC_OP ) ;
2010-09-28 02:15:02 +00:00
glDepthMask ( GL_FALSE ) ;
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
}
2009-02-23 07:23:34 +00:00
2010-09-28 02:15:02 +00:00
void Renderer : : RestoreAPIState ( )
{
// Gets us back into a more game-like state.
glEnable ( GL_SCISSOR_TEST ) ;
2010-12-28 16:16:27 +00:00
SetGenerationMode ( ) ;
2011-09-05 20:04:28 +00:00
BPFunctions : : SetScissor ( ) ;
2010-09-28 02:15:02 +00:00
SetColorMask ( ) ;
2010-12-28 16:16:27 +00:00
SetDepthMode ( ) ;
2010-09-28 02:15:02 +00:00
SetBlendMode ( true ) ;
2013-09-09 21:21:56 +00:00
SetLogicOpMode ( ) ;
2014-02-04 09:45:38 +00:00
SetViewport ( ) ;
2009-03-16 07:54:44 +00:00
2015-12-21 02:49:49 +00:00
const VertexManager * const vm = static_cast < VertexManager * > ( g_vertex_manager . get ( ) ) ;
2012-12-15 16:28:58 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , vm - > m_vertex_buffers ) ;
2014-09-03 04:08:50 +00:00
if ( vm - > m_last_vao )
glBindVertexArray ( vm - > m_last_vao ) ;
2013-10-29 05:23:17 +00:00
2013-01-18 23:39:31 +00:00
TextureCache : : SetStage ( ) ;
2010-09-28 02:15:02 +00:00
}
2009-03-16 07:54:44 +00:00
2010-09-28 02:15:02 +00:00
void Renderer : : SetGenerationMode ( )
{
// none, ccw, cw, ccw
if ( bpmem . genMode . cullmode > 0 )
{
2013-12-30 19:37:59 +00:00
// TODO: GX_CULL_ALL not supported, yet!
2010-09-28 02:15:02 +00:00
glEnable ( GL_CULL_FACE ) ;
glFrontFace ( bpmem . genMode . cullmode = = 2 ? GL_CCW : GL_CW ) ;
2009-03-16 07:54:44 +00:00
}
2010-09-28 02:15:02 +00:00
else
2014-08-15 18:09:53 +00:00
{
2010-09-28 02:15:02 +00:00
glDisable ( GL_CULL_FACE ) ;
2014-08-15 18:09:53 +00:00
}
2010-09-28 02:15:02 +00:00
}
2009-03-16 07:54:44 +00:00
2010-09-28 02:15:02 +00:00
void Renderer : : SetDepthMode ( )
{
2013-01-13 22:35:07 +00:00
const GLenum glCmpFuncs [ 8 ] =
{
GL_NEVER ,
GL_LESS ,
GL_EQUAL ,
GL_LEQUAL ,
GL_GREATER ,
GL_NOTEQUAL ,
GL_GEQUAL ,
GL_ALWAYS
} ;
2010-09-28 02:15:02 +00:00
if ( bpmem . zmode . testenable )
2009-09-13 08:21:35 +00:00
{
2010-09-28 02:15:02 +00:00
glEnable ( GL_DEPTH_TEST ) ;
glDepthMask ( bpmem . zmode . updateenable ? GL_TRUE : GL_FALSE ) ;
glDepthFunc ( glCmpFuncs [ bpmem . zmode . func ] ) ;
2009-09-13 08:21:35 +00:00
}
2010-09-28 02:15:02 +00:00
else
2009-06-08 02:48:38 +00:00
{
2010-09-28 02:15:02 +00:00
// if the test is disabled write is disabled too
2013-02-18 14:54:24 +00:00
// TODO: When PE performance metrics are being emulated via occlusion queries, we should (probably?) enable depth test with depth function ALWAYS here
2010-09-28 02:15:02 +00:00
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( GL_FALSE ) ;
}
}
2009-10-22 20:22:50 +00:00
2010-09-28 02:15:02 +00:00
void Renderer : : SetLogicOpMode ( )
{
2014-01-02 02:06:11 +00:00
if ( GLInterface - > GetMode ( ) ! = GLInterfaceMode : : MODE_OPENGL )
return ;
2013-05-06 04:33:49 +00:00
// Logic ops aren't available in GLES3/GLES2
2013-01-13 22:35:07 +00:00
const GLenum glLogicOpCodes [ 16 ] =
{
GL_CLEAR ,
GL_AND ,
GL_AND_REVERSE ,
GL_COPY ,
GL_AND_INVERTED ,
GL_NOOP ,
GL_XOR ,
GL_OR ,
GL_NOR ,
GL_EQUIV ,
GL_INVERT ,
GL_OR_REVERSE ,
GL_COPY_INVERTED ,
GL_OR_INVERTED ,
GL_NAND ,
GL_SET
} ;
2014-12-16 04:08:54 +00:00
if ( bpmem . blendmode . logicopenable & & ! bpmem . blendmode . blendenable )
2010-09-28 02:15:02 +00:00
{
glEnable ( GL_COLOR_LOGIC_OP ) ;
glLogicOp ( glLogicOpCodes [ bpmem . blendmode . logicmode ] ) ;
}
else
{
glDisable ( GL_COLOR_LOGIC_OP ) ;
}
}
2009-10-22 20:22:50 +00:00
2010-09-28 02:15:02 +00:00
void Renderer : : SetDitherMode ( )
{
if ( bpmem . blendmode . dither )
glEnable ( GL_DITHER ) ;
else
glDisable ( GL_DITHER ) ;
}
2009-10-22 20:22:50 +00:00
2015-03-01 12:04:48 +00:00
void Renderer : : SetSamplerState ( int stage , int texindex , bool custom_tex )
2010-09-28 02:15:02 +00:00
{
2013-02-20 00:22:38 +00:00
auto const & tex = bpmem . tex [ texindex ] ;
auto const & tm0 = tex . texMode0 [ stage ] ;
auto const & tm1 = tex . texMode1 [ stage ] ;
2013-10-29 05:23:17 +00:00
2015-03-01 12:04:48 +00:00
g_sampler_cache - > SetSamplerState ( ( texindex * 4 ) + stage , tm0 , tm1 , custom_tex ) ;
2009-02-28 16:33:59 +00:00
}
2010-08-10 01:08:22 +00:00
2010-09-28 02:15:02 +00:00
void Renderer : : SetInterlacingMode ( )
2009-02-23 07:23:34 +00:00
{
2010-09-28 02:15:02 +00:00
// TODO
2009-02-23 07:23:34 +00:00
}
2013-11-09 23:10:20 +00:00
}
namespace OGL
{
bool Renderer : : SaveScreenshot ( const std : : string & filename , const TargetRectangle & back_rc )
2009-02-27 03:56:34 +00:00
{
2010-07-09 20:56:16 +00:00
u32 W = back_rc . GetWidth ( ) ;
u32 H = back_rc . GetHeight ( ) ;
2014-09-26 03:47:34 +00:00
std : : unique_ptr < u8 [ ] > data ( new u8 [ W * 4 * H ] ) ;
2009-02-27 03:56:34 +00:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2010-08-10 01:08:22 +00:00
2014-09-26 03:47:34 +00:00
glReadPixels ( back_rc . left , back_rc . bottom , W , H , GL_RGBA , GL_UNSIGNED_BYTE , data . get ( ) ) ;
2010-08-10 01:08:22 +00:00
2009-06-06 13:36:33 +00:00
// Turn image upside down
2014-09-26 03:47:34 +00:00
FlipImageData ( data . get ( ) , W , H , 4 ) ;
2013-11-16 21:34:34 +00:00
2014-09-26 03:47:34 +00:00
return TextureToPng ( data . get ( ) , W * 4 , filename , W , H , false ) ;
2013-11-16 21:34:34 +00:00
2009-03-28 21:07:16 +00:00
}
2010-11-18 02:21:26 +00:00
2014-09-25 23:50:25 +00:00
int Renderer : : GetMaxTextureSize ( )
{
int max_size ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & max_size ) ;
return max_size ;
}
2010-12-20 17:06:39 +00:00
}