2013-04-18 03:29:41 +00:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2009-02-23 07:23:34 +00:00
# include "Globals.h"
2009-07-12 21:58:32 +00:00
# include "Thread.h"
2010-01-26 14:56:51 +00:00
# include "Atomic.h"
2009-03-05 23:11:13 +00:00
2009-02-23 07:23:34 +00:00
# include <vector>
# include <cmath>
2009-03-28 21:07:16 +00:00
# include <cstdio>
2009-02-23 07:23:34 +00:00
# include "GLUtil.h"
2013-03-23 19:57:55 +00:00
# if defined(HAVE_WX) && HAVE_WX
2013-02-28 04:37:38 +00:00
# include "WxUtils.h"
2013-03-23 19:57:55 +00:00
# endif
2009-02-23 07:23:34 +00:00
2010-02-02 21:56:29 +00:00
# include "FileUtil.h"
2009-02-23 07:23:34 +00:00
# ifdef _WIN32
# include <mmsystem.h>
# endif
2009-03-28 21:07:16 +00:00
# include "CommonPaths.h"
2013-06-11 13:33:56 +00:00
# include "DriverDetails.h"
2009-09-13 09:23:30 +00:00
# include "VideoConfig.h"
2009-02-23 07:23:34 +00:00
# include "Statistics.h"
# include "ImageWrite.h"
2010-10-24 19:52:52 +00:00
# include "PixelEngine.h"
2009-02-23 07:23:34 +00:00
# include "Render.h"
# include "OpcodeDecoding.h"
2009-06-22 09:31:30 +00:00
# include "BPStructs.h"
2010-09-28 02:15:02 +00:00
# include "TextureCache.h"
2009-10-13 06:12:58 +00:00
# include "RasterFont.h"
2009-02-23 07:23:34 +00:00
# include "VertexShaderGen.h"
2009-08-09 11:03:58 +00:00
# include "DLCache.h"
2009-02-23 07:23:34 +00:00
# include "PixelShaderManager.h"
2011-12-01 03:00:21 +00:00
# include "ProgramShaderCache.h"
2009-02-28 16:33:59 +00:00
# include "VertexShaderManager.h"
2009-02-23 07:23:34 +00:00
# include "VertexLoaderManager.h"
# include "VertexLoader.h"
2009-06-08 19:42:25 +00:00
# include "PostProcessing.h"
2009-06-26 08:57:53 +00:00
# include "TextureConverter.h"
2009-02-23 07:23:34 +00:00
# include "OnScreenDisplay.h"
# include "Timer.h"
2009-06-06 13:36:33 +00:00
# include "StringUtil.h"
2009-06-28 23:35:08 +00:00
# include "FramebufferManager.h"
2009-07-11 02:34:16 +00:00
# include "Fifo.h"
2010-12-05 14:15:36 +00:00
# include "Debugger.h"
2011-01-31 01:28:32 +00:00
# include "Core.h"
2011-06-24 06:50:50 +00:00
# include "Movie.h"
2011-03-15 23:09:12 +00:00
# include "Host.h"
2011-09-05 20:04:28 +00:00
# include "BPFunctions.h"
2012-10-04 03:41:02 +00:00
# include "FPSCounter.h"
2012-11-11 22:57:06 +00:00
# include "ConfigManager.h"
2012-12-15 13:43:01 +00:00
# include "VertexManager.h"
2013-02-20 00:22:38 +00:00
# include "SamplerCache.h"
2013-03-17 18:03:23 +00:00
# include "StreamBuffer.h"
2009-02-23 07:23:34 +00:00
# include "main.h" // Local
# ifdef _WIN32
2010-12-19 19:43:18 +00:00
# include "EmuWindow.h"
2010-11-14 21:14:26 +00:00
# endif
2011-02-11 21:30:53 +00:00
# if defined _WIN32 || defined HAVE_LIBAV
2009-03-28 21:07:16 +00:00
# include "AVIDump.h"
2011-02-11 21:30:53 +00:00
# endif
2009-02-23 07:23:34 +00:00
2009-02-27 03:56:34 +00:00
# if defined(HAVE_WX) && HAVE_WX
# include <wx/image.h>
# endif
2013-04-24 14:24:55 +00:00
// glew1.8 doesn't define KHR_debug
# ifndef GL_DEBUG_OUTPUT
# define GL_DEBUG_OUTPUT 0x92E0
# endif
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
}
# if defined(HAVE_WX) && HAVE_WX
// Screenshot thread struct
typedef struct
{
int W , H ;
std : : string filename ;
wxImage * img ;
} ScrStrct ;
# endif
2010-02-20 04:18:19 +00:00
2009-02-23 07:23:34 +00:00
2011-01-31 03:02:23 +00:00
int OSDInternalW , OSDInternalH ;
2011-01-29 20:16:51 +00:00
namespace OGL
{
2013-03-25 14:45:10 +00:00
enum MultisampleMode {
MULTISAMPLE_OFF ,
MULTISAMPLE_2X ,
MULTISAMPLE_4X ,
MULTISAMPLE_8X ,
MULTISAMPLE_CSAA_8X ,
MULTISAMPLE_CSAA_8XQ ,
MULTISAMPLE_CSAA_16X ,
MULTISAMPLE_CSAA_16XQ ,
MULTISAMPLE_SSAA_4X ,
} ;
2013-03-25 14:14:24 +00:00
VideoConfig g_ogl_config ;
2011-01-29 20:16:51 +00:00
// Declarations and definitions
// ----------------------------
2012-12-07 22:34:38 +00:00
static int s_fps = 0 ;
static GLuint s_ShowEFBCopyRegions_VBO = 0 ;
2012-12-09 21:49:58 +00:00
static GLuint s_ShowEFBCopyRegions_VAO = 0 ;
2013-02-13 12:12:19 +00:00
static SHADER s_ShowEFBCopyRegions ;
2011-01-29 20:16:51 +00:00
2012-12-07 22:34:38 +00:00
static RasterFont * s_pfont = NULL ;
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 ;
2009-03-08 20:04:40 +00:00
static int s_MSAACoverageSamples = 0 ;
2011-05-07 22:00:05 +00:00
static int s_LastMultisampleMode = 0 ;
2009-03-05 23:11:13 +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 ;
2010-05-26 20:46:28 +00:00
# if defined(HAVE_WX) && HAVE_WX
2011-01-27 20:47:58 +00:00
static std : : thread scrshotThread ;
2010-05-26 20:46:28 +00:00
# endif
2010-09-28 02:15:02 +00:00
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 ] ;
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
2011-05-07 22:00:05 +00:00
int GetNumMSAASamples ( int MSAAMode )
2009-02-23 07:23:34 +00:00
{
2013-03-25 14:14:24 +00:00
int samples ;
2011-05-07 22:00:05 +00:00
switch ( MSAAMode )
2009-03-08 20:04:40 +00:00
{
2010-11-18 02:21:26 +00:00
case MULTISAMPLE_OFF :
2013-03-17 09:44:57 +00:00
samples = 1 ;
break ;
2011-05-07 22:00:05 +00:00
2010-11-18 02:21:26 +00:00
case MULTISAMPLE_2X :
2013-03-17 09:44:57 +00:00
samples = 2 ;
break ;
2011-05-07 22:00:05 +00:00
2010-11-18 02:21:26 +00:00
case MULTISAMPLE_4X :
2011-05-07 22:00:05 +00:00
case MULTISAMPLE_CSAA_8X :
case MULTISAMPLE_CSAA_16X :
2013-03-25 14:45:10 +00:00
case MULTISAMPLE_SSAA_4X :
2013-03-17 09:44:57 +00:00
samples = 4 ;
break ;
2011-05-07 22:00:05 +00:00
2010-11-18 02:21:26 +00:00
case MULTISAMPLE_8X :
2011-05-07 22:00:05 +00:00
case MULTISAMPLE_CSAA_8XQ :
case MULTISAMPLE_CSAA_16XQ :
2013-03-17 09:44:57 +00:00
samples = 8 ;
break ;
2011-05-07 22:00:05 +00:00
default :
2013-03-17 09:44:57 +00:00
samples = 1 ;
2011-05-07 22:00:05 +00:00
}
2013-03-17 09:44:57 +00:00
2013-03-25 14:14:24 +00:00
if ( samples < = g_ogl_config . max_samples ) return samples ;
2013-03-17 09:44:57 +00:00
2013-08-27 11:24:23 +00:00
// TODO: move this to InitBackendInfo
OSD : : AddMessage ( StringFromFormat ( " %d Anti Aliasing samples selected, but only %d supported by your GPU. " , samples , g_ogl_config . max_samples ) , 10000 ) ;
2013-03-25 14:14:24 +00:00
return g_ogl_config . max_samples ;
2011-05-07 22:00:05 +00:00
}
int GetNumMSAACoverageSamples ( int MSAAMode )
{
2013-03-17 09:44:57 +00:00
int samples ;
2011-05-07 22:00:05 +00:00
switch ( g_ActiveConfig . iMultisampleMode )
{
2010-08-10 01:08:22 +00:00
case MULTISAMPLE_CSAA_8X :
case MULTISAMPLE_CSAA_8XQ :
2013-03-17 09:44:57 +00:00
samples = 8 ;
break ;
2011-05-07 22:00:05 +00:00
2010-08-10 01:08:22 +00:00
case MULTISAMPLE_CSAA_16X :
case MULTISAMPLE_CSAA_16XQ :
2013-03-17 09:44:57 +00:00
samples = 16 ;
break ;
2011-05-07 22:00:05 +00:00
2010-05-19 03:15:36 +00:00
default :
2013-03-17 09:44:57 +00:00
samples = 0 ;
2009-03-08 20:04:40 +00:00
}
2013-03-25 14:14:24 +00:00
if ( g_ogl_config . bSupportCoverageMSAA | | samples = = 0 ) return samples ;
2013-03-17 09:44:57 +00:00
2013-08-27 11:24:23 +00:00
// TODO: move this to InitBackendInfo
OSD : : AddMessage ( " CSAA Anti Aliasing isn't supported by your GPU. " , 10000 ) ;
2013-03-17 09:44:57 +00:00
return 0 ;
2011-05-07 22:00:05 +00:00
}
2013-03-25 14:45:10 +00:00
void ApplySSAASettings ( ) {
2013-05-06 04:33:49 +00:00
// GLES3 doesn't support SSAA
# ifndef USE_GLES3
2013-03-25 14:45:10 +00:00
if ( g_ActiveConfig . iMultisampleMode = = MULTISAMPLE_SSAA_4X ) {
if ( g_ogl_config . bSupportSampleShading ) {
glEnable ( GL_SAMPLE_SHADING_ARB ) ;
glMinSampleShadingARB ( s_MSAASamples ) ;
} else {
2013-08-27 11:24:23 +00:00
// TODO: move this to InitBackendInfo
OSD : : AddMessage ( " SSAA Anti Aliasing isn't supported by your GPU. " , 10000 ) ;
2013-03-25 14:45:10 +00:00
}
} else if ( g_ogl_config . bSupportSampleShading ) {
glDisable ( GL_SAMPLE_SHADING_ARB ) ;
}
2013-05-06 04:33:49 +00:00
# endif
2013-03-25 14:45:10 +00:00
}
2013-06-27 08:34:53 +00:00
void GLAPIENTRY ErrorCallback ( GLenum source , GLenum type , GLuint id , GLenum severity , GLsizei length , const char * message , void * userParam )
2013-04-04 15:37:16 +00:00
{
2013-05-06 04:33:49 +00:00
// GLES3 doesn't natively support this
// XXX: Include GLES2 extensions header so we can use this
# ifndef USE_GLES3
2013-04-04 15:37:16 +00:00
const char * s_source ;
const char * s_type ;
2013-05-06 04:33:49 +00:00
2013-04-04 15:37:16 +00:00
switch ( source )
{
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 ;
}
switch ( type )
{
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 ;
}
switch ( severity )
{
case GL_DEBUG_SEVERITY_HIGH_ARB : ERROR_LOG ( VIDEO , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
case GL_DEBUG_SEVERITY_MEDIUM_ARB : WARN_LOG ( VIDEO , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
case GL_DEBUG_SEVERITY_LOW_ARB : WARN_LOG ( VIDEO , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
default : ERROR_LOG ( VIDEO , " id: %x, source: %s, type: %s - %s " , id , s_source , s_type , message ) ; break ;
}
2013-05-06 04:33:49 +00:00
# endif
2013-04-04 15:37:16 +00:00
}
2013-06-26 11:14:46 +00:00
# ifndef USE_GLES3
2013-06-25 16:14:41 +00:00
// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
void GLAPIENTRY DepthRangef ( GLfloat neardepth , GLfloat fardepth )
{
glDepthRange ( neardepth , fardepth ) ;
}
void GLAPIENTRY ClearDepthf ( GLfloat depthval )
{
glClearDepth ( depthval ) ;
}
2013-06-26 11:14:46 +00:00
# endif
2013-06-25 16:14:41 +00:00
2013-06-11 13:33:56 +00:00
void InitDriverInfo ( )
{
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 ;
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 " )
vendor = DriverDetails : : VENDOR_NVIDIA ;
2013-08-21 10:34:42 +00:00
else if ( svendor = = " ATI Technologies Inc. " | | svendor = = " Advanced Micro Devices, Inc. " )
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_ATI ;
2013-08-23 08:52:29 +00:00
else if ( std : : string : : npos ! = sversion . find ( " Mesa " ) )
vendor = DriverDetails : : VENDOR_MESA ;
2013-06-11 13:33:56 +00:00
else if ( std : : string : : npos ! = svendor . find ( " Intel " ) )
vendor = DriverDetails : : VENDOR_INTEL ;
else if ( svendor = = " ARM " )
vendor = DriverDetails : : VENDOR_ARM ;
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 " )
vendor = DriverDetails : : VENDOR_QUALCOMM ;
else if ( svendor = = " Imagination Technologies " )
vendor = DriverDetails : : VENDOR_IMGTEC ;
2013-07-03 01:58:09 +00:00
else if ( svendor = = " NVIDIA Corporation " & & srenderer = = " NVIDIA Tegra " )
2013-06-11 13:33:56 +00:00
vendor = DriverDetails : : VENDOR_TEGRA ;
else if ( svendor = = " Vivante Corporation " )
vendor = DriverDetails : : VENDOR_VIVANTE ;
// Get device family and driver version...if we care about it
switch ( vendor )
{
case DriverDetails : : VENDOR_QUALCOMM :
{
if ( std : : string : : npos ! = srenderer . find ( " Adreno (TM) 3 " ) )
2013-08-23 08:52:29 +00:00
driver = DriverDetails : : DRIVER_QUALCOMM_3XX ;
2013-06-11 13:33:56 +00:00
else
2013-08-23 08:52:29 +00:00
driver = DriverDetails : : DRIVER_QUALCOMM_2XX ;
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 :
if ( std : : string : : npos ! = srenderer . find ( " Mali-T6 " ) )
2013-08-23 08:52:29 +00:00
driver = DriverDetails : : DRIVER_ARM_T6XX ;
2013-07-25 05:44:01 +00:00
else if ( std : : string : : npos ! = srenderer . find ( " Mali-4 " ) )
2013-08-23 08:52:29 +00:00
driver = DriverDetails : : DRIVER_ARM_4XX ;
break ;
case DriverDetails : : VENDOR_MESA :
{
if ( svendor = = " nouveau " )
driver = DriverDetails : : DRIVER_NOUVEAU ;
else if ( svendor = = " Intel Open Source Technology Center " )
driver = DriverDetails : : DRIVER_I965 ;
else if ( std : : string : : npos ! = srenderer . find ( " AMD " ) | | std : : string : : npos ! = srenderer . find ( " ATI " ) )
driver = DriverDetails : : DRIVER_R600 ;
int major = 0 ;
int minor = 0 ;
int release = 0 ;
sscanf ( g_ogl_config . gl_version , " %*s Mesa %d.%d.%d " , & major , & minor , & release ) ;
version = 100 * major + 10 * minor + release ;
}
2013-07-25 05:44:01 +00:00
break ;
2013-06-11 13:33:56 +00:00
// We don't care about these
default :
break ;
}
2013-08-23 08:52:29 +00:00
DriverDetails : : Init ( vendor , driver , version ) ;
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_fps = 0 ;
2012-12-07 22:34:38 +00:00
s_ShowEFBCopyRegions_VBO = 0 ;
2011-05-07 22:00:05 +00:00
s_blendMode = 0 ;
2012-10-04 03:41:02 +00:00
InitFPSCounter ( ) ;
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
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 ) ;
2013-06-11 13:33:56 +00:00
InitDriverInfo ( ) ;
2013-05-06 04:33:49 +00:00
// Init extension support.
# ifdef USE_GLES3
// Set default GLES3 options
2013-06-11 13:33:56 +00:00
GLFunc : : Init ( ) ;
2013-05-06 04:33:49 +00:00
WARN_LOG ( VIDEO , " Running the OpenGL ES 3 backend! " ) ;
2013-10-06 08:12:13 +00:00
2013-05-06 04:33:49 +00:00
g_Config . backend_info . bSupportsDualSourceBlend = false ;
2013-09-18 07:36:48 +00:00
g_Config . backend_info . bSupportsGLSLUBO = ! DriverDetails : : HasBug ( DriverDetails : : BUG_ANNIHILATEDUBOS ) ;
2013-09-16 15:43:57 +00:00
g_Config . backend_info . bSupportsPrimitiveRestart = true ;
2013-07-22 10:02:16 +00:00
g_Config . backend_info . bSupportsEarlyZ = false ;
2013-09-18 07:36:48 +00:00
# ifdef ANDROID
g_ogl_config . bSupportsGLSLCache = false ;
# else
2013-07-27 00:42:20 +00:00
g_ogl_config . bSupportsGLSLCache = true ;
2013-09-18 07:36:48 +00:00
# endif
2013-05-06 04:33:49 +00:00
g_ogl_config . bSupportsGLPinnedMemory = false ;
g_ogl_config . bSupportsGLSync = true ;
g_ogl_config . bSupportsGLBaseVertex = false ;
g_ogl_config . bSupportCoverageMSAA = false ; // XXX: GLES3 spec has MSAA
g_ogl_config . bSupportSampleShading = false ;
g_ogl_config . bSupportOGL31 = false ;
2013-10-07 02:51:41 +00:00
if ( DriverDetails : : HasBug ( DriverDetails : : BUG_ISTEGRA ) | | DriverDetails : : HasBug ( DriverDetails : : BUG_ISPOWERVR ) )
2013-10-06 08:12:13 +00:00
g_ogl_config . eSupportedGLSLVersion = GLSLES2 ;
else
g_ogl_config . eSupportedGLSLVersion = GLSLES3 ;
2013-05-06 04:33:49 +00:00
# else
2013-09-02 11:14:45 +00:00
# ifdef __APPLE__
glewExperimental = 1 ;
# endif
if ( glewInit ( ) ! = GLEW_OK )
{
PanicAlert ( " glewInit() failed! Does your video card support OpenGL 2.x? " ) ;
return ;
}
// 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-04-04 15:37:16 +00:00
# if defined(_DEBUG) || defined(DEBUGFAST)
if ( GLEW_ARB_debug_output )
{
glDebugMessageControlARB ( GL_DONT_CARE , GL_DONT_CARE , GL_DONT_CARE , 0 , NULL , true ) ;
glDebugMessageCallbackARB ( ErrorCallback , NULL ) ;
glEnable ( GL_DEBUG_OUTPUT ) ;
}
# endif
2010-08-10 01:08:22 +00:00
2013-09-02 11:14:45 +00:00
if ( ! GLEW_VERSION_2_0 )
2010-08-10 01:08:22 +00:00
{
2013-09-02 11:14:45 +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? " ) ;
2010-06-05 01:38:22 +00:00
bSuccess = false ;
}
2010-08-10 01:08:22 +00:00
2013-01-03 11:06:47 +00:00
if ( ! GLEW_ARB_framebuffer_object )
2010-08-10 01:08:22 +00:00
{
2013-09-02 11:14:45 +00:00
// 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 "
2013-01-03 11:06:47 +00:00
" GPU: Does your video card support OpenGL 3.0? " ) ;
2010-06-05 01:38:22 +00:00
bSuccess = false ;
}
2010-08-10 01:08:22 +00:00
2012-12-09 21:49:58 +00:00
if ( ! GLEW_ARB_vertex_array_object )
{
2013-09-02 11:14:45 +00:00
// 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 "
2012-12-09 21:49:58 +00:00
" GPU: Does your video card support OpenGL 3.0? " ) ;
bSuccess = false ;
}
2012-12-15 13:43:01 +00:00
if ( ! GLEW_ARB_map_buffer_range )
{
2013-09-02 11:14:45 +00:00
// 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 "
2012-12-15 13:43:01 +00:00
" GPU: Does your video card support OpenGL 3.0? " ) ;
bSuccess = false ;
}
2013-03-17 09:06:16 +00:00
if ( ! GLEW_ARB_sampler_objects & & bSuccess )
2013-02-20 03:24:08 +00:00
{
2013-09-02 11:14:45 +00:00
// 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. "
" GPU: Does your video card support OpenGL 3.3? "
2013-03-17 09:06:16 +00:00
" Please report this issue, then there will be a workaround " ) ;
2013-02-20 03:24:08 +00:00
bSuccess = false ;
}
2013-06-25 16:14:41 +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 ( ! GLEW_ARB_ES2_compatibility )
{
glDepthRangef = DepthRangef ;
glClearDepthf = ClearDepthf ;
}
2013-01-21 17:44:33 +00:00
2013-02-04 20:11:12 +00:00
g_Config . backend_info . bSupportsDualSourceBlend = GLEW_ARB_blend_func_extended ;
g_Config . backend_info . bSupportsGLSLUBO = GLEW_ARB_uniform_buffer_object ;
2013-04-10 10:58:52 +00:00
g_Config . backend_info . bSupportsPrimitiveRestart = GLEW_VERSION_3_1 | | GLEW_NV_primitive_restart ;
2013-07-22 10:02:16 +00:00
g_Config . backend_info . bSupportsEarlyZ = GLEW_ARB_shader_image_load_store ;
2013-03-25 14:14:24 +00:00
g_ogl_config . bSupportsGLSLCache = GLEW_ARB_get_program_binary ;
g_ogl_config . bSupportsGLPinnedMemory = GLEW_AMD_pinned_memory ;
g_ogl_config . bSupportsGLSync = GLEW_ARB_sync ;
g_ogl_config . bSupportsGLBaseVertex = GLEW_ARB_draw_elements_base_vertex ;
g_ogl_config . bSupportCoverageMSAA = GLEW_NV_framebuffer_multisample_coverage ;
2013-03-25 14:45:10 +00:00
g_ogl_config . bSupportSampleShading = GLEW_ARB_sample_shading ;
2013-04-10 10:58:52 +00:00
g_ogl_config . bSupportOGL31 = GLEW_VERSION_3_1 ;
2013-05-06 04:33:49 +00:00
2013-09-03 18:56:24 +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-04-08 12:50:58 +00:00
{
2013-09-03 18:56:24 +00:00
PanicAlert ( " GPU: OGL ERROR: Need at least GLSL 1.30 \n "
" GPU: Does your video card support OpenGL 3.0? \n "
2013-04-19 13:21:45 +00:00
" GPU: Your driver supports GLSL %s " , g_ogl_config . glsl_version ) ;
2013-04-08 12:50:58 +00:00
bSuccess = false ;
}
else if ( strstr ( g_ogl_config . glsl_version , " 1.30 " ) )
{
g_ogl_config . eSupportedGLSLVersion = GLSL_130 ;
2013-07-22 10:02:16 +00:00
g_Config . backend_info . bSupportsEarlyZ = false ; // layout keyword is only supported on glsl150+
2013-04-08 12:50:58 +00:00
}
2013-07-22 10:02:16 +00:00
else if ( strstr ( g_ogl_config . glsl_version , " 1.40 " ) )
2013-04-08 12:50:58 +00:00
{
g_ogl_config . eSupportedGLSLVersion = GLSL_140 ;
2013-07-22 10:02:16 +00:00
g_Config . backend_info . bSupportsEarlyZ = false ; // layout keyword is only supported on glsl150+
}
else
{
g_ogl_config . eSupportedGLSLVersion = GLSL_150 ;
2013-04-08 12:50:58 +00:00
}
2013-09-02 11:14:45 +00:00
# endif
if ( ! bSuccess )
{
// Not all needed extensions are supported, so we have to stop here.
// Else some of the next calls might crash.
return ;
}
2013-03-25 14:14:24 +00:00
glGetIntegerv ( GL_MAX_SAMPLES , & g_ogl_config . max_samples ) ;
2013-04-05 05:08:32 +00:00
if ( g_ogl_config . max_samples < 1 )
g_ogl_config . max_samples = 1 ;
2013-03-07 20:07:57 +00:00
2013-08-23 08:52:29 +00:00
if ( g_Config . backend_info . bSupportsGLSLUBO & & DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENUBO ) )
{
2013-03-07 20:07:57 +00:00
g_Config . backend_info . bSupportsGLSLUBO = false ;
2013-03-31 23:10:21 +00:00
ERROR_LOG ( VIDEO , " Buggy driver detected. Disable UBO " ) ;
2013-08-23 08:52:29 +00:00
OSD : : AddMessage ( " Major performance warning: Buggy GPU driver detected. " , 20000 ) ;
OSD : : AddMessage ( " Please either install the closed-source GPU driver or update your Mesa 3D version. " , 20000 ) ;
2013-03-07 20:07:57 +00:00
}
2013-03-17 09:06:16 +00:00
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-03-25 14:14:24 +00:00
2013-07-22 10:02:16 +00:00
WARN_LOG ( VIDEO , " Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s " ,
2013-02-17 20:41:00 +00:00
g_ActiveConfig . backend_info . bSupportsDualSourceBlend ? " " : " DualSourceBlend " ,
g_ActiveConfig . backend_info . bSupportsGLSLUBO ? " " : " UniformBuffer " ,
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 " ,
g_ogl_config . bSupportsGLSync ? " " : " Sync " ,
2013-03-25 14:45:10 +00:00
g_ogl_config . bSupportCoverageMSAA ? " " : " CSAA " ,
g_ogl_config . bSupportSampleShading ? " " : " SSAA "
2013-04-04 16:55:37 +00:00
) ;
2011-12-21 03:55:11 +00:00
2011-05-07 22:00:05 +00:00
s_LastMultisampleMode = g_ActiveConfig . iMultisampleMode ;
s_MSAASamples = GetNumMSAASamples ( s_LastMultisampleMode ) ;
s_MSAACoverageSamples = GetNumMSAACoverageSamples ( s_LastMultisampleMode ) ;
2013-03-25 14:45:10 +00:00
ApplySSAASettings ( ) ;
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 ( ) ;
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
2010-09-30 15:24:34 +00:00
s_LastEFBScale = 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
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 ;
2012-12-24 17:09:52 +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
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 ) ;
2013-04-10 10:58:52 +00:00
if ( g_ActiveConfig . backend_info . bSupportsPrimitiveRestart )
{
2013-09-16 15:43:57 +00:00
# ifdef USE_GLES3
glEnable ( GL_PRIMITIVE_RESTART_FIXED_INDEX ) ;
# else
2013-04-10 10:58:52 +00:00
if ( g_ogl_config . bSupportOGL31 )
{
glEnable ( GL_PRIMITIVE_RESTART ) ;
glPrimitiveRestartIndex ( 65535 ) ;
}
else
{
glEnableClientState ( GL_PRIMITIVE_RESTART_NV ) ;
glPrimitiveRestartIndexNV ( 65535 ) ;
}
2013-05-06 04:33:49 +00:00
# endif
2013-09-16 15:43:57 +00:00
}
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ( ) ;
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
{
# if defined(HAVE_WX) && HAVE_WX
if ( scrshotThread . joinable ( ) )
scrshotThread . join ( ) ;
# endif
}
void Renderer : : Shutdown ( )
2010-06-05 01:38:22 +00:00
{
2013-07-22 13:41:10 +00:00
delete g_framebuffer_manager ;
2009-09-06 15:11:21 +00:00
g_Config . bRunning = false ;
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ( ) ;
2012-12-07 22:34:38 +00:00
glDeleteBuffers ( 1 , & s_ShowEFBCopyRegions_VBO ) ;
2012-12-09 21:49:58 +00:00
glDeleteVertexArrays ( 1 , & s_ShowEFBCopyRegions_VAO ) ;
2012-12-07 22:34:38 +00:00
s_ShowEFBCopyRegions_VBO = 0 ;
2010-06-05 01:38:22 +00:00
delete s_pfont ;
2009-09-03 19:24:16 +00:00
s_pfont = 0 ;
2013-02-13 12:12:19 +00:00
s_ShowEFBCopyRegions . Destroy ( ) ;
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
g_framebuffer_manager = new FramebufferManager ( s_target_width , s_target_height ,
s_MSAASamples , s_MSAACoverageSamples ) ;
2013-01-25 19:39:19 +00:00
s_pfont = new RasterFont ( ) ;
2013-02-13 12:12:19 +00:00
ProgramShaderCache : : CompileShader ( s_ShowEFBCopyRegions ,
2013-04-08 12:50:58 +00:00
" ATTRIN vec2 rawpos; \n "
" ATTRIN vec3 color0; \n "
" VARYOUT vec4 c; \n "
2013-01-25 19:39:19 +00:00
" void main(void) { \n "
2013-10-06 08:12:13 +00:00
" gl_Position = vec4(rawpos, 0.0, 1.0); \n "
" c = vec4(color0, 1.0); \n "
2013-02-13 12:12:19 +00:00
" } \n " ,
2013-04-08 12:50:58 +00:00
" VARYIN vec4 c; \n "
2013-10-06 08:12:13 +00:00
" COLOROUT(ocol0) \n "
2013-02-13 12:12:19 +00:00
" void main(void) { \n "
" ocol0 = c; \n "
" } \n " ) ;
2013-01-25 19:39:19 +00:00
// creating buffers
glGenBuffers ( 1 , & s_ShowEFBCopyRegions_VBO ) ;
glGenVertexArrays ( 1 , & s_ShowEFBCopyRegions_VAO ) ;
glBindBuffer ( GL_ARRAY_BUFFER , s_ShowEFBCopyRegions_VBO ) ;
glBindVertexArray ( s_ShowEFBCopyRegions_VAO ) ;
glEnableVertexAttribArray ( SHADER_POSITION_ATTRIB ) ;
glVertexAttribPointer ( SHADER_POSITION_ATTRIB , 2 , GL_FLOAT , 0 , sizeof ( GLfloat ) * 5 , NULL ) ;
glEnableVertexAttribArray ( SHADER_COLOR0_ATTRIB ) ;
glVertexAttribPointer ( SHADER_COLOR0_ATTRIB , 3 , GL_FLOAT , 0 , sizeof ( GLfloat ) * 5 , ( GLfloat * ) NULL + 2 ) ;
2009-09-03 19:24:16 +00:00
}
2009-02-23 07:23:34 +00:00
2010-09-28 02:15:02 +00:00
// Create On-Screen-Messages
2010-11-18 02:21:26 +00:00
void Renderer : : DrawDebugInfo ( )
2009-02-23 07:23:34 +00:00
{
2010-09-28 02:15:02 +00:00
// Reset viewport for drawing text
2012-12-17 20:54:20 +00:00
glViewport ( 0 , 0 , GLInterface - > GetBackBufferWidth ( ) , GLInterface - > GetBackBufferHeight ( ) ) ;
2010-09-28 02:15:02 +00:00
// Draw various messages on the screen, like FPS, statistics, etc.
char debugtext_buffer [ 8192 ] ;
char * p = debugtext_buffer ;
p [ 0 ] = 0 ;
2009-02-23 07:23:34 +00:00
2010-09-28 02:15:02 +00:00
if ( g_ActiveConfig . bShowFPS )
p + = sprintf ( p , " FPS: %d \n " , s_fps ) ;
2009-02-23 07:23:34 +00:00
2012-11-14 21:21:54 +00:00
if ( SConfig : : GetInstance ( ) . m_ShowLag )
2012-12-07 01:25:07 +00:00
p + = sprintf ( p , " Lag: %llu \n " , Movie : : g_currentLagCount ) ;
2012-11-11 22:57:06 +00:00
2011-02-17 09:12:36 +00:00
if ( g_ActiveConfig . bShowInputDisplay )
2011-06-24 06:50:50 +00:00
p + = sprintf ( p , " %s " , Movie : : GetInputDisplay ( ) . c_str ( ) ) ;
2011-02-17 09:12:36 +00:00
2013-07-25 05:44:01 +00:00
# ifndef USE_GLES3
2010-09-28 02:15:02 +00:00
if ( g_ActiveConfig . bShowEFBCopyRegions )
{
// Set Line Size
glLineWidth ( 3.0f ) ;
2009-02-23 07:23:34 +00:00
2012-12-07 21:49:18 +00:00
// 2*Coords + 3*Color
2013-08-19 17:20:10 +00:00
u32 length = stats . efb_regions . size ( ) * sizeof ( GLfloat ) * ( 2 + 3 ) * 2 * 6 ;
2012-12-07 22:34:38 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , s_ShowEFBCopyRegions_VBO ) ;
2013-08-19 17:20:10 +00:00
glBufferData ( GL_ARRAY_BUFFER , length , NULL , GL_STREAM_DRAW ) ;
GLfloat * Vertices = ( GLfloat * ) glMapBufferRange ( GL_ARRAY_BUFFER , 0 , length , GL_MAP_WRITE_BIT ) ;
2010-08-10 01:08:22 +00:00
2010-09-28 02:15:02 +00:00
// Draw EFB copy regions rectangles
2012-10-27 23:10:31 +00:00
int a = 0 ;
2012-12-07 21:49:18 +00:00
GLfloat color [ 3 ] = { 0.0f , 1.0f , 1.0f } ;
2010-09-28 02:15:02 +00:00
for ( std : : vector < EFBRectangle > : : const_iterator it = stats . efb_regions . begin ( ) ;
it ! = stats . efb_regions . end ( ) ; + + it )
{
GLfloat halfWidth = EFB_WIDTH / 2.0f ;
GLfloat halfHeight = EFB_HEIGHT / 2.0f ;
GLfloat x = ( GLfloat ) - 1.0f + ( ( GLfloat ) it - > left / halfWidth ) ;
GLfloat y = ( GLfloat ) 1.0f - ( ( GLfloat ) it - > top / halfHeight ) ;
GLfloat x2 = ( GLfloat ) - 1.0f + ( ( GLfloat ) it - > right / halfWidth ) ;
GLfloat y2 = ( GLfloat ) 1.0f - ( ( GLfloat ) it - > bottom / halfHeight ) ;
2009-02-23 07:23:34 +00:00
2012-12-07 21:49:18 +00:00
Vertices [ a + + ] = x ;
Vertices [ a + + ] = y ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
2012-10-27 23:10:31 +00:00
2012-12-07 21:49:18 +00:00
Vertices [ a + + ] = x2 ;
Vertices [ a + + ] = y ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
2012-10-27 23:10:31 +00:00
2012-12-07 21:49:18 +00:00
Vertices [ a + + ] = x2 ;
Vertices [ a + + ] = y ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x2 ;
Vertices [ a + + ] = y2 ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x2 ;
Vertices [ a + + ] = y2 ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x ;
Vertices [ a + + ] = y2 ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x ;
Vertices [ a + + ] = y2 ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x ;
Vertices [ a + + ] = y ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x ;
Vertices [ a + + ] = y ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x2 ;
Vertices [ a + + ] = y2 ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x2 ;
Vertices [ a + + ] = y ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
Vertices [ a + + ] = x ;
Vertices [ a + + ] = y2 ;
Vertices [ a + + ] = color [ 0 ] ;
Vertices [ a + + ] = color [ 1 ] ;
Vertices [ a + + ] = color [ 2 ] ;
// TO DO: build something nicer here
GLfloat temp = color [ 0 ] ;
color [ 0 ] = color [ 1 ] ;
color [ 1 ] = color [ 2 ] ;
color [ 2 ] = temp ;
2010-09-28 02:15:02 +00:00
}
2012-12-07 22:34:38 +00:00
glUnmapBuffer ( GL_ARRAY_BUFFER ) ;
2012-10-27 23:10:31 +00:00
2013-02-13 12:12:19 +00:00
s_ShowEFBCopyRegions . Bind ( ) ;
2012-12-09 21:49:58 +00:00
glBindVertexArray ( s_ShowEFBCopyRegions_VAO ) ;
2012-12-07 21:49:18 +00:00
glDrawArrays ( GL_LINES , 0 , stats . efb_regions . size ( ) * 2 * 6 ) ;
2009-02-23 07:23:34 +00:00
2010-09-28 02:15:02 +00:00
// Restore Line Size
2013-03-25 14:14:24 +00:00
SetLineWidth ( ) ;
2009-02-23 07:23:34 +00:00
2010-09-28 02:15:02 +00:00
// Clear stored regions
stats . efb_regions . clear ( ) ;
}
2013-07-25 05:44:01 +00:00
# endif
2010-01-07 20:01:41 +00:00
2010-09-28 02:15:02 +00:00
if ( g_ActiveConfig . bOverlayStats )
p = Statistics : : ToString ( p ) ;
2009-07-15 00:51:24 +00:00
2010-09-28 02:15:02 +00:00
if ( g_ActiveConfig . bOverlayProjStats )
p = Statistics : : ToStringProj ( p ) ;
2009-07-15 00:51:24 +00:00
2010-09-28 02:15:02 +00:00
// Render a shadow, and then the text.
if ( p ! = debugtext_buffer )
2009-07-15 00:51:24 +00:00
{
2010-09-28 02:15:02 +00:00
Renderer : : RenderText ( debugtext_buffer , 21 , 21 , 0xDD000000 ) ;
Renderer : : RenderText ( debugtext_buffer , 20 , 20 , 0xFF00FFFF ) ;
}
}
void Renderer : : RenderText ( const char * text , int left , int top , u32 color )
{
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
2010-09-28 02:15:02 +00:00
s_pfont - > printMultilineText ( text ,
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-11-18 02:21:26 +00:00
2010-09-28 02:15:02 +00:00
GL_REPORT_ERRORD ( ) ;
}
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
2011-09-05 20:04:28 +00:00
void Renderer : : SetScissorRect ( const TargetRectangle & rc )
2009-02-23 07:23:34 +00:00
{
2011-09-05 20:04:28 +00:00
glScissor ( rc . left , rc . bottom , rc . GetWidth ( ) , rc . 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 ;
if ( bpmem . blendmode . alphaupdate & & ( bpmem . zcontrol . pixel_format = = PIXELFMT_RGBA6_Z24 ) )
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 ( )
{
for ( u32 i = 0 ; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT ; + + i )
s_efbCacheValid [ 0 ] [ i ] = false ;
for ( u32 i = 0 ; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT ; + + i )
s_efbCacheValid [ 1 ] [ i ] = false ;
}
void Renderer : : UpdateEFBCache ( EFBAccessType type , u32 cacheRectIdx , const EFBRectangle & efbPixelRc , const TargetRectangle & targetPixelRc , const u32 * data )
{
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 ;
s_efbCache [ cacheType ] [ cacheRectIdx ] [ yCache * EFB_CACHE_RECT_SIZE + xCache ] = data [ yData * targetPixelRcWidth + xData ] ;
}
}
s_efbCacheValid [ cacheType ] [ cacheRectIdx ] = true ;
}
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:
// - GX_PokeAlphaRead
// The behavior of EFB pokes can be modified by:
// - 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
{
2010-09-30 15:24:34 +00:00
if ( ! g_ActiveConfig . bEFBAccessEnable )
2010-09-28 02:15:02 +00:00
return 0 ;
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
// Get the rectangular target region containing the EFB pixel
2010-09-28 02:15:02 +00:00
EFBRectangle efbPixelRc ;
2011-08-22 04:15:02 +00:00
efbPixelRc . left = ( x / EFB_CACHE_RECT_SIZE ) * EFB_CACHE_RECT_SIZE ;
efbPixelRc . top = ( y / EFB_CACHE_RECT_SIZE ) * EFB_CACHE_RECT_SIZE ;
2012-07-23 17:56:57 +00:00
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 ) ;
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
u32 z ;
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 ( ) ;
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-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
2011-08-22 04:15:02 +00:00
u32 * depthMap = new u32 [ 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 ,
GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , depthMap ) ;
GL_REPORT_ERRORD ( ) ;
UpdateEFBCache ( type , cacheRectIdx , efbPixelRc , targetPixelRc , depthMap ) ;
delete [ ] depthMap ;
}
u32 xRect = x % EFB_CACHE_RECT_SIZE ;
u32 yRect = y % EFB_CACHE_RECT_SIZE ;
z = s_efbCache [ 0 ] [ cacheRectIdx ] [ yRect * EFB_CACHE_RECT_SIZE + xRect ] ;
2010-09-28 02:15:02 +00:00
// Scale the 32-bit value returned by glReadPixels to a 24-bit
// value (GC uses a 24-bit Z-buffer).
// TODO: in RE0 this value is often off by one, which causes lighting to disappear
2010-12-27 03:18:01 +00:00
if ( bpmem . zcontrol . pixel_format = = PIXELFMT_RGB565_Z16 )
{
2010-12-27 18:09:03 +00:00
// if Z is in 16 bit format you must return a 16 bit integer
2010-12-27 03:18:01 +00:00
z = z > > 16 ;
}
else
{
z = z > > 8 ;
}
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
u32 color ;
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 ( ) ;
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-08-26 20:18:00 +00:00
g_renderer - > RestoreAPIState ( ) ;
2011-08-22 04:15:02 +00:00
}
u32 * colorMap = new u32 [ targetPixelRcWidth * targetPixelRcHeight ] ;
2013-05-06 04:33:49 +00:00
# ifdef USE_GLES3
// XXX: Swap colours
glReadPixels ( targetPixelRc . left , targetPixelRc . bottom , targetPixelRcWidth , targetPixelRcHeight ,
2013-07-13 22:24:23 +00:00
GL_RGBA , GL_UNSIGNED_BYTE , colorMap ) ;
2013-05-06 04:33:49 +00:00
# else
2011-08-22 04:15:02 +00:00
glReadPixels ( targetPixelRc . left , targetPixelRc . bottom , targetPixelRcWidth , targetPixelRcHeight ,
GL_BGRA , GL_UNSIGNED_INT_8_8_8_8_REV , colorMap ) ;
2013-05-06 04:33:49 +00:00
# endif
2011-08-22 04:15:02 +00:00
GL_REPORT_ERRORD ( ) ;
2010-09-28 02:15:02 +00:00
2011-08-22 04:15:02 +00:00
UpdateEFBCache ( type , cacheRectIdx , efbPixelRc , targetPixelRc , colorMap ) ;
2010-09-28 02:15:02 +00:00
2011-08-22 04:15:02 +00:00
delete [ ] colorMap ;
}
u32 xRect = x % EFB_CACHE_RECT_SIZE ;
u32 yRect = y % EFB_CACHE_RECT_SIZE ;
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)
PixelEngine : : UPEAlphaReadReg alpha_read_mode ;
2011-01-07 19:51:28 +00:00
PixelEngine : : Read16 ( ( u16 & ) alpha_read_mode , PE_ALPHAREAD ) ;
2010-12-27 03:18:01 +00:00
if ( bpmem . zcontrol . pixel_format = = PIXELFMT_RGBA6_Z24 )
{
color = RGBA8ToRGBA6ToRGBA8 ( color ) ;
}
else if ( bpmem . zcontrol . pixel_format = = PIXELFMT_RGB565_Z16 )
{
2010-12-27 18:09:03 +00:00
color = RGBA8ToRGB565ToRGBA8 ( color ) ;
}
2010-12-27 03:18:01 +00:00
if ( bpmem . zcontrol . pixel_format ! = PIXELFMT_RGBA6_Z24 )
{
color | = 0xFF000000 ;
}
2010-10-24 19:52:52 +00:00
if ( alpha_read_mode . ReadMode = = 2 ) return color ; // GX_READ_NONE
else if ( alpha_read_mode . ReadMode = = 1 ) return ( color | 0xFF000000 ) ; // GX_READ_FF
else /*if(alpha_read_mode.ReadMode == 0)*/ return ( color & 0x00FFFFFF ) ; // GX_READ_00
2010-09-28 02:15:02 +00:00
}
case POKE_COLOR :
2010-12-27 18:09:03 +00:00
case POKE_Z :
2010-09-28 02:15:02 +00:00
// TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
// the exact location. Note: EFB pokes are susceptible to Z-buffering
// and perhaps blending.
//WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
break ;
default :
break ;
}
return 0 ;
}
// Called from VertexShaderManager
2011-05-12 02:14:45 +00:00
void Renderer : : UpdateViewport ( Matrix44 & vpCorrection )
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?
2011-04-11 01:49:32 +00:00
int X = EFBToScaledX ( ( int ) ceil ( xfregs . viewport . xOrig - xfregs . viewport . wd - ( float ) scissorXOff ) ) ;
int Y = EFBToScaledY ( ( int ) ceil ( ( float ) EFB_HEIGHT - xfregs . viewport . yOrig + xfregs . viewport . ht + ( float ) scissorYOff ) ) ;
int Width = EFBToScaledX ( ( int ) ceil ( 2.0f * xfregs . viewport . wd ) ) ;
int Height = EFBToScaledY ( ( int ) ceil ( - 2.0f * xfregs . viewport . ht ) ) ;
double GLNear = ( xfregs . viewport . farZ - xfregs . viewport . zRange ) / 16777216.0f ;
double GLFar = xfregs . viewport . farZ / 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
// OpenGL does not require any viewport correct
Matrix44 : : LoadIdentity ( vpCorrection ) ;
2010-09-28 02:15:02 +00:00
// Update the view port
2010-09-30 15:24:34 +00:00
glViewport ( X , Y , Width , Height ) ;
2013-05-06 04:33:49 +00:00
glDepthRangef ( GLNear , GLFar ) ;
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
2013-05-06 04:33:49 +00:00
glClearDepthf ( float ( z & 0xFFFFFF ) / float ( 0xFFFFFF ) ) ;
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
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.
2013-02-18 17:49:20 +00:00
bool target_has_alpha = bpmem . zcontrol . pixel_format = = PIXELFMT_RGBA6_Z24 ;
2013-03-16 23:36:13 +00:00
bool useDstAlpha = ! g_ActiveConfig . bDstAlphaPass & & bpmem . dstalpha . enable & & bpmem . blendmode . alphaupdate & & target_has_alpha ;
bool useDualSource = useDstAlpha & & g_ActiveConfig . backend_info . bSupportsDualSourceBlend ;
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 )
newval | = 0x0049 ; // enable blending src 1 dst 1
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 )
// blend enable change
( newval & 1 ) ? glEnable ( GL_BLEND ) : glDisable ( GL_BLEND ) ;
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 ;
2011-12-29 06:32:06 +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 )
{
2013-03-28 21:59:42 +00:00
srcidx = GX_BL_ONE ;
dstidx = GX_BL_ZERO ;
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
2013-03-28 21:59:42 +00:00
if ( srcidx = = GX_BL_DSTCLR ) srcidx = GX_BL_DSTALPHA ;
if ( srcidx = = GX_BL_INVDSTCLR ) srcidx = GX_BL_INVDSTALPHA ;
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
2013-03-28 21:59:42 +00:00
if ( dstidx = = GX_BL_SRCCLR ) dstidx = GX_BL_SRCALPHA ;
if ( dstidx = = GX_BL_INVSRCCLR ) dstidx = GX_BL_INVSRCALPHA ;
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
}
2013-02-27 01:47:48 +00:00
void DumpFrame ( const std : : vector < u8 > & data , int w , int h )
{
# if defined(HAVE_LIBAV) || defined(_WIN32)
if ( g_ActiveConfig . bDumpFrames & & ! data . empty ( ) )
{
AVIDump : : AddFrame ( & data [ 0 ] , w , h ) ;
}
# endif
}
2009-06-29 07:30:48 +00:00
// This function has the final picture. We adjust the aspect ratio here.
2013-09-23 06:29:31 +00:00
void Renderer : : Swap ( u32 xfbAddr , u32 fbWidth , u32 fbHeight , const EFBRectangle & rc , float Gamma )
2009-02-28 16:33:59 +00:00
{
2011-02-11 18:59:42 +00:00
static int w = 0 , h = 0 ;
2012-09-28 21:19:50 +00:00
if ( 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 ;
2010-11-14 23:31:53 +00:00
const XFBSourceBase * const * xfbSourceList = FramebufferManager : : GetXFBSource ( xfbAddr , fbWidth , 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
2013-03-07 16:00:11 +00:00
PostProcessing : : Update ( s_backbuffer_width , s_backbuffer_height ) ;
2012-09-28 22:04:55 +00:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height ) ;
TargetRectangle flipped_trc = GetTargetRectangle ( ) ;
// Flip top and bottom for some reason; TODO: Fix the code to suck less?
int tmp = flipped_trc . top ;
flipped_trc . top = flipped_trc . bottom ;
flipped_trc . bottom = tmp ;
2013-03-07 16:00:11 +00:00
2009-06-26 08:57:53 +00:00
GL_REPORT_ERRORD ( ) ;
2009-03-08 19:19:51 +00:00
2013-01-03 19:44:47 +00:00
// Copy the framebuffer to screen.
2010-03-10 06:45:13 +00:00
2010-11-14 23:31:53 +00:00
const XFBSourceBase * xfbSource = NULL ;
2010-03-10 06:45:13 +00:00
2010-07-02 17:09:53 +00:00
if ( g_ActiveConfig . bUseXFB )
2009-06-26 08:57:53 +00:00
{
2013-03-07 16:00:11 +00:00
// Render to the real/postprocessing buffer now.
PostProcessing : : BindTargetFramebuffer ( ) ;
2013-01-09 00:50:52 +00:00
2010-07-02 17:09:53 +00:00
// draw each xfb source
2013-01-03 19:44:47 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , FramebufferManager : : GetXFBFramebuffer ( ) ) ;
2010-07-12 19:30:25 +00:00
2010-07-02 17:09:53 +00:00
for ( u32 i = 0 ; i < xfbCount ; + + i )
2010-03-10 06:45:13 +00:00
{
2010-07-02 17:09:53 +00:00
xfbSource = xfbSourceList [ i ] ;
2010-03-10 06:45:13 +00:00
2010-07-02 17:09:53 +00:00
MathUtil : : Rectangle < float > drawRc ;
2010-03-10 06:45:13 +00:00
2012-09-28 21:21:09 +00:00
if ( g_ActiveConfig . bUseRealXFB )
{
2013-01-03 19:44:47 +00:00
drawRc . top = flipped_trc . top ;
drawRc . bottom = flipped_trc . bottom ;
drawRc . left = flipped_trc . left ;
drawRc . right = flipped_trc . right ;
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 ;
int hOffset = ( ( s32 ) xfbSource - > srcAddr - ( s32 ) xfbAddr ) / ( ( s32 ) fbWidth * 2 ) ;
2013-01-03 19:44:47 +00:00
2013-03-25 22:23:32 +00:00
drawRc . top = flipped_trc . top - hOffset * flipped_trc . GetHeight ( ) / fbHeight ;
drawRc . bottom = flipped_trc . top - ( hOffset + xfbHeight ) * flipped_trc . GetHeight ( ) / fbHeight ;
2013-01-03 19:44:47 +00:00
drawRc . left = flipped_trc . left + ( flipped_trc . GetWidth ( ) - xfbWidth * flipped_trc . GetWidth ( ) / fbWidth ) / 2 ;
drawRc . right = flipped_trc . left + ( flipped_trc . GetWidth ( ) + xfbWidth * flipped_trc . GetWidth ( ) / fbWidth ) / 2 ;
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;
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
2010-11-14 23:31:53 +00:00
MathUtil : : Rectangle < float > sourceRc ;
sourceRc . left = xfbSource - > sourceRc . left ;
sourceRc . right = xfbSource - > sourceRc . right ;
sourceRc . top = xfbSource - > sourceRc . top ;
sourceRc . bottom = xfbSource - > sourceRc . bottom ;
xfbSource - > Draw ( sourceRc , drawRc , 0 , 0 ) ;
2010-07-02 17:09:53 +00:00
}
}
else
{
2010-09-30 15:24:34 +00:00
TargetRectangle targetRc = ConvertEFBRectangle ( rc ) ;
2012-12-13 14:48:42 +00:00
2013-01-09 00:50:52 +00:00
// for msaa mode, we must resolve the efb content to non-msaa
FramebufferManager : : ResolveAndGetRenderTarget ( rc ) ;
2012-12-08 01:01:35 +00:00
2013-03-07 16:00:11 +00:00
// Render to the real/postprocessing buffer now. (resolve have changed this in msaa mode)
PostProcessing : : BindTargetFramebuffer ( ) ;
2012-12-13 14:48:42 +00:00
2013-01-09 00:50:52 +00:00
// always the non-msaa fbo
GLuint fb = s_MSAASamples > 1 ? FramebufferManager : : GetResolvedFramebuffer ( ) : FramebufferManager : : GetEFBFramebuffer ( ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , fb ) ;
2013-01-03 19:44:47 +00:00
glBlitFramebuffer ( targetRc . left , targetRc . bottom , targetRc . right , targetRc . top ,
flipped_trc . left , flipped_trc . bottom , flipped_trc . right , flipped_trc . top ,
GL_COLOR_BUFFER_BIT , GL_LINEAR ) ;
2009-06-26 08:57:53 +00:00
}
2013-03-07 16:00:11 +00:00
PostProcessing : : BlitToScreen ( ) ;
2010-09-30 15:24:34 +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
{
2011-03-05 06:11:26 +00:00
std : : lock_guard < std : : mutex > lk ( s_criticalScreenshot ) ;
2012-09-28 22:04:55 +00:00
SaveScreenshot ( s_sScreenshotName , flipped_trc ) ;
2009-06-07 11:51:53 +00:00
// Reset settings
2010-11-18 02:21:26 +00:00
s_sScreenshotName . clear ( ) ;
2009-06-07 11:51:53 +00:00
s_bScreenshot = false ;
}
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
# ifndef USE_GLES3
2011-03-11 12:56:26 +00:00
# if defined _WIN32 || defined HAVE_LIBAV
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bDumpFrames )
2009-06-08 10:16:08 +00:00
{
2011-03-05 06:11:26 +00:00
std : : lock_guard < std : : mutex > lk ( s_criticalScreenshot ) ;
2013-02-27 01:47:48 +00:00
if ( frame_data . empty ( ) | | w ! = flipped_trc . GetWidth ( ) | |
2012-09-28 22:04:55 +00:00
h ! = flipped_trc . GetHeight ( ) )
2011-02-11 18:59:42 +00:00
{
2012-09-28 22:04:55 +00:00
w = flipped_trc . GetWidth ( ) ;
h = flipped_trc . GetHeight ( ) ;
2013-02-27 01:47:48 +00:00
frame_data . resize ( 3 * w * h ) ;
2011-02-11 18:59:42 +00:00
}
2009-03-28 21:07:16 +00:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2013-02-27 01:47:48 +00:00
glReadPixels ( flipped_trc . left , flipped_trc . bottom , w , h , GL_BGR , GL_UNSIGNED_BYTE , & frame_data [ 0 ] ) ;
2010-08-03 10:48:49 +00:00
if ( GL_REPORT_ERROR ( ) = = GL_NO_ERROR & & w > 0 & & h > 0 )
2009-04-03 14:35:49 +00:00
{
2011-09-08 13:39:03 +00:00
if ( ! bLastFrameDumped )
2009-04-03 14:35:49 +00:00
{
2010-11-14 21:14:26 +00:00
# ifdef _WIN32
2011-09-08 15:09:24 +00:00
bAVIDumping = AVIDump : : Start ( EmuWindow : : GetParentWnd ( ) , w , h ) ;
2010-11-14 21:14:26 +00:00
# else
2011-09-08 15:09:24 +00:00
bAVIDumping = AVIDump : : Start ( w , h ) ;
2010-11-14 21:14:26 +00:00
# endif
2011-09-08 15:09:24 +00:00
if ( ! bAVIDumping )
2009-06-08 10:16:08 +00:00
OSD : : AddMessage ( " AVIDump Start failed " , 2000 ) ;
2010-06-05 01:38:22 +00:00
else
2009-04-03 14:35:49 +00:00
{
2009-06-08 10:16:08 +00:00
OSD : : AddMessage ( StringFromFormat (
2010-11-18 16:46:17 +00:00
" Dumping Frames to \" %sframedump0.avi \" (%dx%d RGB24) " ,
2011-02-28 20:40:15 +00:00
File : : GetUserPath ( D_DUMPFRAMES_IDX ) . c_str ( ) , w , h ) . c_str ( ) , 2000 ) ;
2009-03-28 21:07:16 +00:00
}
}
2011-09-08 15:09:24 +00:00
if ( bAVIDumping )
2010-11-14 21:14:26 +00:00
{
2013-02-27 01:47:48 +00:00
# ifndef _WIN32
FlipImageData ( & frame_data [ 0 ] , w , h ) ;
2010-11-14 21:14:26 +00:00
# endif
2013-02-27 01:47:48 +00:00
AVIDump : : AddFrame ( & frame_data [ 0 ] , w , h ) ;
2010-11-14 21:14:26 +00:00
}
2009-04-03 14:35:49 +00:00
2011-09-08 13:39:03 +00:00
bLastFrameDumped = true ;
2009-03-28 21:07:16 +00:00
}
2009-06-08 10:16:08 +00:00
else
NOTICE_LOG ( VIDEO , " Error reading framebuffer " ) ;
2010-06-05 01:38:22 +00:00
}
else
2009-04-03 14:35:49 +00:00
{
2011-09-08 15:09:24 +00:00
if ( bLastFrameDumped & & bAVIDumping )
2009-04-03 14:35:49 +00:00
{
2013-02-27 01:47:48 +00:00
std : : vector < u8 > ( ) . swap ( frame_data ) ;
w = h = 0 ;
2009-03-28 21:07:16 +00:00
AVIDump : : Stop ( ) ;
2011-09-08 15:09:24 +00:00
bAVIDumping = false ;
2010-11-14 21:14:26 +00:00
OSD : : AddMessage ( " Stop dumping frames " , 2000 ) ;
2009-03-28 21:07:16 +00:00
}
2011-09-08 13:39:03 +00:00
bLastFrameDumped = false ;
2009-03-28 21:07:16 +00:00
}
# else
2010-08-10 01:08:22 +00:00
if ( g_ActiveConfig . bDumpFrames )
{
2011-03-05 12:05:58 +00:00
std : : lock_guard < std : : mutex > lk ( s_criticalScreenshot ) ;
2011-02-28 20:40:15 +00:00
std : : string movie_file_name ;
2012-09-28 22:04:55 +00:00
w = GetTargetRectangle ( ) . GetWidth ( ) ;
h = GetTargetRectangle ( ) . GetHeight ( ) ;
2013-02-27 01:47:48 +00:00
frame_data . resize ( 3 * w * h ) ;
2009-03-28 21:07:16 +00:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2013-02-27 01:47:48 +00:00
glReadPixels ( GetTargetRectangle ( ) . left , GetTargetRectangle ( ) . bottom , w , h , GL_BGR , GL_UNSIGNED_BYTE , & frame_data [ 0 ] ) ;
2010-08-10 01:08:22 +00:00
if ( GL_REPORT_ERROR ( ) = = GL_NO_ERROR )
{
2011-09-08 15:09:24 +00:00
if ( ! bLastFrameDumped )
2010-08-10 01:08:22 +00:00
{
2011-02-28 20:40:15 +00:00
movie_file_name = File : : GetUserPath ( D_DUMPFRAMES_IDX ) + " framedump.raw " ;
2011-09-08 15:09:24 +00:00
pFrameDump . Open ( movie_file_name , " wb " ) ;
if ( ! pFrameDump )
2010-08-10 01:08:22 +00:00
OSD : : AddMessage ( " Error opening framedump.raw for writing. " , 2000 ) ;
else
{
2013-02-27 01:59:33 +00:00
OSD : : AddMessage ( StringFromFormat ( " Dumping Frames to \" %s \" (%dx%d RGB24) " , movie_file_name . c_str ( ) , w , h ) . c_str ( ) , 2000 ) ;
2009-03-28 21:07:16 +00:00
}
}
2011-09-08 15:09:24 +00:00
if ( pFrameDump )
2010-08-10 01:08:22 +00:00
{
2013-02-27 01:47:48 +00:00
FlipImageData ( & frame_data [ 0 ] , w , h ) ;
pFrameDump . WriteBytes ( & frame_data [ 0 ] , w * 3 * h ) ;
2011-09-08 15:09:24 +00:00
pFrameDump . Flush ( ) ;
2009-03-28 21:07:16 +00:00
}
2011-09-08 15:09:24 +00:00
bLastFrameDumped = true ;
2009-03-28 21:07:16 +00:00
}
2010-08-10 01:08:22 +00:00
}
else
{
2011-09-08 15:09:24 +00:00
if ( bLastFrameDumped )
pFrameDump . Close ( ) ;
bLastFrameDumped = false ;
2009-03-28 21:07:16 +00:00
}
# endif
2013-05-06 11:43:04 +00:00
# endif
2010-09-28 02:15:02 +00:00
// Finish up the current frame, print some stats
2011-01-07 04:57:59 +00:00
2011-01-25 03:30:12 +00:00
SetWindowSize ( fbWidth , 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
2010-05-19 03:15:36 +00:00
bool xfbchanged = false ;
2010-09-28 02:15:02 +00:00
2012-09-28 21:48:18 +00:00
if ( FramebufferManagerBase : : LastXfbWidth ( ) ! = fbWidth | | FramebufferManagerBase : : LastXfbHeight ( ) ! = fbHeight )
2010-05-19 03:15:36 +00:00
{
xfbchanged = true ;
2013-01-29 22:40:15 +00:00
unsigned int const last_w = ( fbWidth < 1 | | fbWidth > MAX_XFB_WIDTH ) ? MAX_XFB_WIDTH : fbWidth ;
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 ( ) ;
2010-09-30 15:24:34 +00:00
if ( W ! = s_backbuffer_width | | H ! = s_backbuffer_height | | s_LastEFBScale ! = 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 ;
2010-09-30 15:24:34 +00:00
s_LastEFBScale = g_ActiveConfig . iEFBScale ;
2010-05-19 03:15:36 +00:00
}
2011-05-07 22:00:05 +00:00
if ( xfbchanged | | WindowResized | | ( s_LastMultisampleMode ! = g_ActiveConfig . iMultisampleMode ) )
2010-06-05 01:38:22 +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
2012-09-28 22:19:28 +00:00
if ( CalculateTargetSize ( s_backbuffer_width , s_backbuffer_height ) | | s_LastMultisampleMode ! = g_ActiveConfig . iMultisampleMode )
2010-05-19 03:15:36 +00:00
{
2011-05-07 22:00:05 +00:00
s_LastMultisampleMode = g_ActiveConfig . iMultisampleMode ;
s_MSAASamples = GetNumMSAASamples ( s_LastMultisampleMode ) ;
s_MSAACoverageSamples = GetNumMSAACoverageSamples ( s_LastMultisampleMode ) ;
2013-03-25 14:45:10 +00:00
ApplySSAASettings ( ) ;
2010-11-14 23:31:53 +00:00
delete g_framebuffer_manager ;
g_framebuffer_manager = new FramebufferManager ( s_target_width , s_target_height ,
2010-09-28 02:15:02 +00:00
s_MSAASamples , s_MSAACoverageSamples ) ;
2010-05-19 03:15:36 +00:00
}
}
2010-09-28 02:15:02 +00:00
if ( XFBWrited )
2012-10-04 03:41:02 +00:00
s_fps = UpdateFPSCounter ( ) ;
2009-06-07 12:06:15 +00:00
// ---------------------------------------------------------------------
2013-09-18 07:36:48 +00:00
if ( ! DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENSWAP ) )
{
GL_REPORT_ERRORD ( ) ;
2010-08-10 01:08:22 +00:00
2013-09-18 07:36:48 +00:00
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2009-06-07 12:06:15 +00:00
2013-09-18 07:36:48 +00:00
DrawDebugInfo ( ) ;
DrawDebugText ( ) ;
GL_REPORT_ERRORD ( ) ;
2010-08-10 01:08:22 +00:00
2013-09-18 07:36:48 +00:00
// Do our OSD callbacks
OSD : : DoCallbacks ( OSD : : OSD_ONFRAME ) ;
OSD : : DrawMessages ( ) ;
GL_REPORT_ERRORD ( ) ;
}
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-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-08-08 01:39:56 +00:00
2009-06-08 20:07:20 +00:00
// Clear framebuffer
2013-09-18 07:36:48 +00:00
if ( ! DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENSWAP ) )
{
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
GL_REPORT_ERRORD ( ) ;
}
2009-06-07 12:06:15 +00:00
2013-03-30 21:17:39 +00:00
if ( s_vsync ! = g_ActiveConfig . IsVSync ( ) )
{
s_vsync = g_ActiveConfig . IsVSync ( ) ;
GLInterface - > SwapInterval ( s_vsync ) ;
}
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.
2009-08-09 11:03:58 +00:00
DLCache : : ProgressiveCleanup ( ) ;
2010-09-28 02:15:02 +00:00
TextureCache : : Cleanup ( ) ;
2009-06-07 12:06:15 +00:00
2010-06-05 01:38:22 +00:00
frameCount + + ;
2009-06-07 12:06:15 +00:00
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_FRAME , true ) ;
2010-09-28 02:15:02 +00:00
// Begin new frame
// Set default viewport and scissor, for the clear to work correctly
2010-06-05 01:38:22 +00:00
// New frame
stats . ResetFrame ( ) ;
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
GL_REPORT_ERRORD ( ) ;
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
RestoreAPIState ( ) ;
2009-09-13 17:46:33 +00:00
GL_REPORT_ERRORD ( ) ;
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-07-13 22:24:23 +00:00
// SaveTexture("tex.tga", GL_TEXTURE_2D, s_FakeZTarget,
2010-11-18 02:21:26 +00:00
// GetTargetWidth(), GetTargetHeight());
2011-01-31 01:28:32 +00:00
Core : : Callback_VideoCopiedToXFB ( XFBWrited | | ( g_ActiveConfig . bUseXFB & & g_ActiveConfig . bUseRealXFB ) ) ;
2010-03-25 22:01:33 +00:00
XFBWrited = false ;
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-09-09 21:21:56 +00:00
# ifndef USE_GLES3
glDisable ( GL_COLOR_LOGIC_OP ) ;
# endif
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 ( ) ;
2011-05-12 02:14:45 +00:00
VertexShaderManager : : SetViewportChanged ( ) ;
2009-03-16 07:54:44 +00:00
2013-05-06 04:33:49 +00:00
# ifndef USE_GLES3
2011-11-30 04:21:43 +00:00
glPolygonMode ( GL_FRONT_AND_BACK , g_ActiveConfig . bWireFrame ? GL_LINE : GL_FILL ) ;
2013-05-06 04:33:49 +00:00
# endif
2012-12-15 13:43:01 +00:00
VertexManager * vm = ( OGL : : VertexManager * ) g_vertex_manager ;
2012-12-15 16:28:58 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , vm - > m_vertex_buffers ) ;
2012-12-15 13:43:01 +00:00
vm - > m_last_vao = 0 ;
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 )
{
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
glDisable ( GL_CULL_FACE ) ;
}
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 ( )
{
2013-05-06 04:33:49 +00:00
// Logic ops aren't available in GLES3/GLES2
# ifndef USE_GLES3
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
} ;
if ( bpmem . blendmode . logicopenable )
2010-09-28 02:15:02 +00:00
{
glEnable ( GL_COLOR_LOGIC_OP ) ;
glLogicOp ( glLogicOpCodes [ bpmem . blendmode . logicmode ] ) ;
}
else
{
glDisable ( GL_COLOR_LOGIC_OP ) ;
}
2013-05-06 04:33:49 +00:00
# endif
2010-09-28 02:15:02 +00:00
}
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
2010-09-28 02:15:02 +00:00
void Renderer : : SetLineWidth ( )
{
2011-04-11 01:49:32 +00:00
float fratio = xfregs . viewport . wd ! = 0 ?
2010-09-28 02:15:02 +00:00
( ( float ) Renderer : : GetTargetWidth ( ) / EFB_WIDTH ) : 1.0f ;
if ( bpmem . lineptwidth . linesize > 0 )
// scale by ratio of widths
glLineWidth ( ( float ) bpmem . lineptwidth . linesize * fratio / 6.0f ) ;
2013-05-06 04:33:49 +00:00
# ifndef USE_GLES3
2010-09-28 02:15:02 +00:00
if ( bpmem . lineptwidth . pointsize > 0 )
glPointSize ( ( float ) bpmem . lineptwidth . pointsize * fratio / 6.0f ) ;
2013-05-06 04:33:49 +00:00
# endif
2010-09-28 02:15:02 +00:00
}
2009-10-22 20:22:50 +00:00
2010-09-28 02:15:02 +00:00
void Renderer : : SetSamplerState ( int stage , int texindex )
{
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-02-26 17:30:13 +00:00
g_sampler_cache - > SetSamplerState ( ( texindex * 4 ) + stage , tm0 , tm1 ) ;
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
}
2010-09-28 02:15:02 +00:00
void Renderer : : FlipImageData ( u8 * data , int w , int h )
{
// Flip image upside down. Damn OpenGL.
for ( int y = 0 ; y < h / 2 ; y + + )
{
for ( int x = 0 ; x < w ; x + + )
{
std : : swap ( data [ ( y * w + x ) * 3 ] , data [ ( ( h - 1 - y ) * w + x ) * 3 ] ) ;
std : : swap ( data [ ( y * w + x ) * 3 + 1 ] , data [ ( ( h - 1 - y ) * w + x ) * 3 + 1 ] ) ;
std : : swap ( data [ ( y * w + x ) * 3 + 2 ] , data [ ( ( h - 1 - y ) * w + x ) * 3 + 2 ] ) ;
}
}
}
2010-11-18 02:21:26 +00:00
}
2011-01-31 01:28:32 +00:00
// TODO: remove
extern bool g_aspect_wide ;
2009-07-31 01:55:26 +00:00
# if defined(HAVE_WX) && HAVE_WX
2011-01-27 20:47:58 +00:00
void TakeScreenshot ( ScrStrct * threadStruct )
2009-07-29 03:11:35 +00:00
{
// These will contain the final image size
float FloatW = ( float ) threadStruct - > W ;
float FloatH = ( float ) threadStruct - > H ;
// Handle aspect ratio for the final ScrStrct to look exactly like what's on screen.
2010-01-13 21:11:02 +00:00
if ( g_ActiveConfig . iAspectRatio ! = ASPECT_STRETCH )
2009-07-29 03:11:35 +00:00
{
2011-01-31 01:28:32 +00:00
bool use16_9 = g_aspect_wide ;
2010-08-10 01:08:22 +00:00
2010-01-13 21:11:02 +00:00
// Check for force-settings and override.
if ( g_ActiveConfig . iAspectRatio = = ASPECT_FORCE_16_9 )
use16_9 = true ;
else if ( g_ActiveConfig . iAspectRatio = = ASPECT_FORCE_4_3 )
use16_9 = false ;
2010-08-10 01:08:22 +00:00
2010-01-13 21:11:02 +00:00
float Ratio = ( FloatW / FloatH ) / ( ! use16_9 ? ( 4.0f / 3.0f ) : ( 16.0f / 9.0f ) ) ;
2010-08-10 01:08:22 +00:00
2009-07-29 03:11:35 +00:00
// If ratio > 1 the picture is too wide and we have to limit the width.
if ( Ratio > 1 )
FloatW / = Ratio ;
// ratio == 1 or the image is too high, we have to limit the height.
else
FloatH * = Ratio ;
2010-08-10 01:08:22 +00:00
2009-07-31 01:55:26 +00:00
// This is a bit expensive on high resolutions
2009-07-29 03:11:35 +00:00
threadStruct - > img - > Rescale ( ( int ) FloatW , ( int ) FloatH , wxIMAGE_QUALITY_HIGH ) ;
}
// Save the screenshot and finally kill the wxImage object
2009-07-31 01:55:26 +00:00
// This is really expensive when saving to PNG, but not at all when using BMP
2013-02-28 08:39:06 +00:00
threadStruct - > img - > SaveFile ( StrToWxStr ( threadStruct - > filename ) ,
2010-09-28 02:15:02 +00:00
wxBITMAP_TYPE_PNG ) ;
2009-07-29 03:11:35 +00:00
threadStruct - > img - > Destroy ( ) ;
2010-08-10 01:08:22 +00:00
2009-07-29 03:11:35 +00:00
// Show success messages
2010-08-10 01:08:22 +00:00
OSD : : AddMessage ( StringFromFormat ( " Saved %i x %i %s " , ( int ) FloatW , ( int ) FloatH ,
2013-08-23 23:44:16 +00:00
threadStruct - > filename . c_str ( ) ) , 2000 ) ;
2009-07-31 01:55:26 +00:00
delete threadStruct ;
2009-07-29 03:11:35 +00:00
}
2009-07-31 01:55:26 +00:00
# endif
2009-07-29 03:11:35 +00:00
2010-11-18 02:21:26 +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 ( ) ;
2011-03-23 02:06:40 +00:00
u8 * data = ( u8 * ) malloc ( ( sizeof ( u8 ) * 3 * W * H ) ) ;
2009-02-27 03:56:34 +00:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2010-08-10 01:08:22 +00:00
2010-07-09 20:56:16 +00:00
glReadPixels ( back_rc . left , back_rc . bottom , W , H , GL_RGB , GL_UNSIGNED_BYTE , data ) ;
2010-08-10 01:08:22 +00:00
2009-06-06 17:34:54 +00:00
// Show failure message
2010-08-03 10:48:49 +00:00
if ( GL_REPORT_ERROR ( ) ! = GL_NO_ERROR )
2009-06-06 17:34:54 +00:00
{
2011-03-23 02:06:40 +00:00
free ( data ) ;
2009-06-06 13:36:33 +00:00
OSD : : AddMessage ( " Error capturing or saving screenshot. " , 2000 ) ;
2009-06-06 17:34:54 +00:00
return false ;
}
2010-08-10 01:08:22 +00:00
2009-06-06 13:36:33 +00:00
// Turn image upside down
FlipImageData ( data , W , H ) ;
2010-08-10 01:08:22 +00:00
2009-03-28 21:07:16 +00:00
# if defined(HAVE_WX) && HAVE_WX
2009-06-06 13:36:33 +00:00
// Create wxImage
2009-07-29 03:11:35 +00:00
wxImage * a = new wxImage ( W , H , data ) ;
2010-08-10 01:08:22 +00:00
2011-01-27 20:47:58 +00:00
if ( scrshotThread . joinable ( ) )
scrshotThread . join ( ) ;
2010-08-10 01:08:22 +00:00
2009-07-29 03:11:35 +00:00
ScrStrct * threadStruct = new ScrStrct ;
2010-11-18 02:21:26 +00:00
threadStruct - > filename = filename ;
2009-07-29 03:11:35 +00:00
threadStruct - > img = a ;
threadStruct - > H = H ; threadStruct - > W = W ;
2010-08-10 01:08:22 +00:00
2011-01-27 20:47:58 +00:00
scrshotThread = std : : thread ( TakeScreenshot , threadStruct ) ;
2009-07-31 01:55:26 +00:00
# ifdef _WIN32
2011-01-27 20:47:58 +00:00
SetThreadPriority ( scrshotThread . native_handle ( ) , THREAD_PRIORITY_BELOW_NORMAL ) ;
2009-07-31 01:55:26 +00:00
# endif
2009-03-28 21:07:16 +00:00
bool result = true ;
2010-08-10 01:08:22 +00:00
2009-07-29 03:11:35 +00:00
OSD : : AddMessage ( " Saving Screenshot... " , 2000 ) ;
2010-08-10 01:08:22 +00:00
2009-03-28 21:07:16 +00:00
# else
2010-11-18 02:21:26 +00:00
bool result = SaveTGA ( filename . c_str ( ) , W , H , data ) ;
2011-03-23 02:06:40 +00:00
free ( data ) ;
2009-07-29 00:49:12 +00:00
# endif
2010-08-10 01:08:22 +00:00
2009-03-28 21:07:16 +00:00
return result ;
}
2010-11-18 02:21:26 +00:00
2010-12-20 17:06:39 +00:00
}