2009-07-28 21:32:10 +00:00
// Copyright (C) 2003 Dolphin Project.
2009-02-23 07:23:34 +00:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
2009-06-07 12:06:15 +00:00
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"
#include <Cg/cg.h>
#include <Cg/cgGL.h>
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"
2009-09-13 09:23:30 +00:00
#include "VideoConfig.h"
2009-02-23 07:23:34 +00:00
#include "Profiler.h"
#include "Statistics.h"
#include "ImageWrite.h"
#include "Render.h"
#include "OpcodeDecoding.h"
2009-06-22 09:31:30 +00:00
#include "BPStructs.h"
2009-02-23 07:23:34 +00:00
#include "TextureMngr.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 "PixelShaderCache.h"
#include "PixelShaderManager.h"
2009-02-28 16:33:59 +00:00
#include "VertexShaderCache.h"
#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 "XFB.h"
#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"
2009-02-23 07:23:34 +00:00
#include "main.h" // Local
#ifdef _WIN32
#include "OS/Win32.h"
2009-03-28 21:07:16 +00:00
#include "AVIDump.h"
2009-02-23 07:23:34 +00:00
#endif
2009-02-27 03:56:34 +00:00
#if defined(HAVE_WX) && HAVE_WX
#include <wx/image.h>
#endif
2009-06-07 12:06:15 +00:00
// Declarations and definitions
2009-09-08 16:07:13 +00:00
// ----------------------------
2010-02-20 04:18:19 +00:00
int s_fps = 0 ;
2009-02-23 07:23:34 +00:00
CGcontext g_cgcontext ;
CGprofile g_cgvProf ;
CGprofile g_cgfProf ;
RasterFont * s_pfont = NULL ;
2009-03-28 21:07:16 +00:00
static bool s_bLastFrameDumped = false ;
#ifdef _WIN32
static bool s_bAVIDumping = false ;
#else
static FILE * f_pFrameDump ;
#endif
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 ;
2009-03-05 23:11:13 +00:00
2009-06-29 21:54:42 +00:00
bool s_bHaveFramebufferBlit = false ; // export to FramebufferManager.cpp
2009-03-08 20:04:40 +00:00
static bool s_bHaveCoverageMSAA = false ;
2009-03-08 19:19:51 +00:00
static u32 s_blendMode ;
2009-02-23 07:23:34 +00:00
2009-02-28 16:33:59 +00:00
static volatile bool s_bScreenshot = false ;
2010-05-26 20:46:28 +00:00
#if defined(HAVE_WX) && HAVE_WX
2009-07-31 01:55:26 +00:00
static Common :: Thread * scrshotThread = 0 ;
2010-05-26 20:46:28 +00:00
#endif
2009-02-27 03:56:34 +00:00
static Common :: CriticalSection s_criticalScreenshot ;
static std :: string s_sScreenshotName ;
2009-02-23 07:23:34 +00:00
int frameCount ;
2009-02-28 16:33:59 +00:00
2009-09-06 15:11:21 +00:00
// The custom resolution
2009-03-05 23:11:13 +00:00
// TODO: Add functionality to reinit all the render targets when the window is resized.
2009-09-06 15:11:21 +00:00
static int m_CustomWidth ;
static int m_CustomHeight ;
// The framebuffer size
static int m_FrameBufferWidth ;
static int m_FrameBufferHeight ;
2009-02-28 16:33:59 +00:00
2009-06-29 20:54:47 +00:00
static GLuint s_tempScreenshotFramebuffer = 0 ;
2009-06-28 23:35:08 +00:00
2010-05-26 20:46:28 +00:00
static unsigned int s_XFB_width ;
static unsigned int s_XFB_height ;
2010-05-19 03:15:36 +00:00
static float xScale ;
static float yScale ;
static int EFBxScale ;
static int EFByScale ;
2009-08-08 01:39:56 +00:00
static bool s_skipSwap = false ;
2009-06-09 21:29:54 +00:00
#ifndef _WIN32
int OSDChoice = 0 , OSDTime = 0 , OSDInternalW = 0 , OSDInternalH = 0 ;
#endif
2009-02-23 07:23:34 +00:00
2009-03-05 23:11:13 +00:00
namespace {
2009-02-23 07:23:34 +00:00
2009-07-31 01:55:26 +00:00
#if defined(HAVE_WX) && HAVE_WX
2009-07-29 03:11:35 +00:00
// Screenshot thread struct
typedef struct
{
int W , H ;
std :: string filename ;
wxImage * img ;
} ScrStrct ;
2009-07-31 01:55:26 +00:00
#endif
2009-07-29 03:11:35 +00:00
2009-02-23 07:23:34 +00:00
static const GLenum glSrcFactors [ 8 ] =
{
2010-06-05 01:38:22 +00:00
GL_ZERO ,
GL_ONE ,
GL_DST_COLOR ,
GL_ONE_MINUS_DST_COLOR ,
GL_SRC_ALPHA ,
GL_ONE_MINUS_SRC_ALPHA ,
GL_DST_ALPHA ,
GL_ONE_MINUS_DST_ALPHA
2009-02-23 07:23:34 +00:00
};
static const GLenum glDestFactors [ 8 ] = {
2010-06-05 01:38:22 +00:00
GL_ZERO ,
2009-10-25 02:35:21 +00:00
GL_ONE ,
GL_SRC_COLOR ,
GL_ONE_MINUS_SRC_COLOR ,
2010-06-05 01:38:22 +00:00
GL_SRC_ALPHA ,
2009-10-25 02:35:21 +00:00
GL_ONE_MINUS_SRC_ALPHA ,
GL_DST_ALPHA ,
GL_ONE_MINUS_DST_ALPHA
2009-02-23 07:23:34 +00:00
};
2009-11-27 19:42:27 +00:00
static const GLenum glCmpFuncs [ 8 ] = {
2010-05-19 03:15:36 +00:00
GL_NEVER ,
GL_LESS ,
GL_EQUAL ,
GL_LEQUAL ,
GL_GREATER ,
GL_NOTEQUAL ,
GL_GEQUAL ,
GL_ALWAYS
2009-11-27 19:42:27 +00:00
};
static const GLenum glLogicOpCodes [ 16 ] = {
2010-06-05 01:38:22 +00:00
GL_CLEAR ,
2010-05-19 03:15:36 +00:00
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
2009-11-27 19:42:27 +00:00
};
2009-03-05 23:11:13 +00:00
void SetDefaultRectTexParams ()
{
// Set some standard texture filter modes.
2010-06-05 01:38:22 +00:00
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE );
if ( glGetError () != GL_NO_ERROR ) {
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S , GL_CLAMP );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T , GL_CLAMP );
GL_REPORT_ERRORD ();
}
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER , GL_LINEAR );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER , GL_LINEAR );
2009-03-05 23:11:13 +00:00
}
2009-04-08 17:58:58 +00:00
void HandleCgError ( CGcontext ctx , CGerror err , void * appdata )
{
2009-06-09 19:40:47 +00:00
DEBUG_LOG ( VIDEO , "Cg error: %s" , cgGetErrorString ( err ));
2009-04-08 17:58:58 +00:00
const char * listing = cgGetLastListing ( g_cgcontext );
if ( listing != NULL ) {
2009-06-09 19:40:47 +00:00
DEBUG_LOG ( VIDEO , " last listing: %s" , listing );
2009-04-08 17:58:58 +00:00
}
}
2009-03-05 23:11:13 +00:00
2009-06-07 12:06:15 +00:00
} // namespace
2009-09-18 19:56:49 +00:00
void VideoConfig :: UpdateProjectionHack ()
{
:: UpdateProjectionHack ( g_Config . iPhackvalue );
}
2009-03-05 23:11:13 +00:00
2009-06-07 12:06:15 +00:00
// Init functions
2009-02-23 07:23:34 +00:00
bool Renderer :: Init ()
{
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ();
2010-06-05 01:38:22 +00:00
bool bSuccess = true ;
2009-02-28 16:33:59 +00:00
s_blendMode = 0 ;
2009-03-08 20:04:40 +00:00
s_MSAACoverageSamples = 0 ;
2009-09-13 08:21:35 +00:00
switch ( g_ActiveConfig . iMultisampleMode )
2009-03-08 20:04:40 +00:00
{
2010-05-19 03:15:36 +00:00
case MULTISAMPLE_OFF : s_MSAASamples = 1 ; break ;
case MULTISAMPLE_2X : s_MSAASamples = 2 ; break ;
case MULTISAMPLE_4X : s_MSAASamples = 4 ; break ;
case MULTISAMPLE_8X : s_MSAASamples = 8 ; break ;
case MULTISAMPLE_CSAA_8X : s_MSAASamples = 4 ; s_MSAACoverageSamples = 8 ; break ;
case MULTISAMPLE_CSAA_8XQ : s_MSAASamples = 8 ; s_MSAACoverageSamples = 8 ; break ;
case MULTISAMPLE_CSAA_16X : s_MSAASamples = 4 ; s_MSAACoverageSamples = 16 ; break ;
case MULTISAMPLE_CSAA_16XQ : s_MSAASamples = 8 ; s_MSAACoverageSamples = 16 ; break ;
default :
2009-03-08 20:04:40 +00:00
s_MSAASamples = 1 ;
}
2009-02-28 16:33:59 +00:00
GLint numvertexattribs = 0 ;
2010-06-05 01:38:22 +00:00
g_cgcontext = cgCreateContext ();
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
cgGetError ();
2009-03-08 19:19:51 +00:00
cgSetErrorHandler ( HandleCgError , NULL );
2009-03-05 23:11:13 +00:00
2010-06-05 01:38:22 +00:00
// Look for required extensions.
const char * ptoken = ( const char * ) glGetString ( GL_EXTENSIONS );
2009-02-28 16:33:59 +00:00
if ( ! ptoken )
{
2009-04-03 21:32:10 +00:00
PanicAlert ( "Your OpenGL Driver seems to be not working. \n "
2010-06-05 01:38:22 +00:00
"Please make sure your drivers are up-to-date and \n "
2009-04-03 21:01:05 +00:00
"that your video hardware is OpenGL 2.x compatible "
);
2009-02-28 16:33:59 +00:00
return false ;
}
2009-07-31 01:55:26 +00:00
2010-06-05 01:38:22 +00:00
INFO_LOG ( VIDEO , "Supported OpenGL Extensions:" );
INFO_LOG ( VIDEO , ptoken ); // write to the log file
INFO_LOG ( VIDEO , "" );
2009-02-23 07:23:34 +00:00
2009-04-03 20:22:45 +00:00
OSD :: AddMessage ( StringFromFormat ( "Video Info: %s, %s, %s" , ( const char * ) glGetString ( GL_VENDOR ),
( const char * ) glGetString ( GL_RENDERER ),
( const char * ) glGetString ( GL_VERSION )). c_str (), 5000 );
2009-02-28 16:33:59 +00:00
glGetIntegerv ( GL_MAX_VERTEX_ATTRIBS , & numvertexattribs );
2010-06-05 01:38:22 +00:00
if ( numvertexattribs < 11 ) {
ERROR_LOG ( VIDEO , "********* \n GPU: OGL ERROR: Number of attributes %d not enough \n GPU: *********Does your video card support OpenGL 2.x?" , numvertexattribs );
bSuccess = false ;
}
2009-02-23 07:23:34 +00:00
2009-02-28 16:33:59 +00:00
// Init extension support.
if ( glewInit () != GLEW_OK ) {
2010-06-05 01:38:22 +00:00
ERROR_LOG ( VIDEO , "glewInit() failed!Does your video card support OpenGL 2.x?" );
return false ;
}
if ( ! GLEW_EXT_framebuffer_object ) {
ERROR_LOG ( VIDEO , "********* \n GPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets \n GPU: *********Does your video card support OpenGL 2.x?" );
bSuccess = false ;
}
if ( ! GLEW_EXT_secondary_color ) {
ERROR_LOG ( VIDEO , "********* \n GPU: OGL ERROR: Need GL_EXT_secondary_color \n GPU: *********Does your video card support OpenGL 2.x?" );
bSuccess = false ;
}
2009-03-08 19:19:51 +00:00
s_bHaveFramebufferBlit = strstr ( ptoken , "GL_EXT_framebuffer_blit" ) != NULL ;
if ( ! s_bHaveFramebufferBlit )
{
// MSAA ain't gonna work. turn it off if enabled.
s_MSAASamples = 1 ;
}
2009-03-08 20:04:40 +00:00
s_bHaveCoverageMSAA = strstr ( ptoken , "GL_NV_framebuffer_multisample_coverage" ) != NULL ;
if ( ! s_bHaveCoverageMSAA )
{
s_MSAACoverageSamples = 0 ;
}
2010-06-05 01:38:22 +00:00
if ( ! bSuccess )
return false ;
2009-02-23 07:23:34 +00:00
2009-03-05 23:11:13 +00:00
// Handle VSync on/off
2009-09-09 20:47:11 +00:00
#if defined USE_WX && USE_WX
// TODO: FILL IN
#elif defined _WIN32
2009-02-28 16:33:59 +00:00
if ( WGLEW_EXT_swap_control )
2009-09-13 08:21:35 +00:00
wglSwapIntervalEXT ( g_ActiveConfig . bVSync ? 1 : 0 );
2009-02-28 16:33:59 +00:00
else
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , "no support for SwapInterval (framerate clamped to monitor refresh rate) Does your video card support OpenGL 2. x ? ") ;
2009-02-23 07:23:34 +00:00
#elif defined(HAVE_X11) && HAVE_X11
2009-02-28 16:33:59 +00:00
if ( glXSwapIntervalSGI )
2009-09-13 08:21:35 +00:00
glXSwapIntervalSGI ( g_ActiveConfig . bVSync ? 1 : 0 );
2009-02-28 16:33:59 +00:00
else
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , "no support for SwapInterval (framerate clamped to monitor refresh rate)") ;
2009-02-23 07:23:34 +00:00
#endif
2010-06-05 01:38:22 +00:00
// check the max texture width and height
2009-02-23 07:23:34 +00:00
GLint max_texture_size ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , ( GLint * ) & max_texture_size );
if ( max_texture_size < 1024 ) {
2009-02-28 01:26:56 +00:00
ERROR_LOG ( VIDEO , "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024" , max_texture_size );
2009-02-23 07:23:34 +00:00
}
2009-03-22 11:21:44 +00:00
if ( GL_REPORT_ERROR () != GL_NO_ERROR )
bSuccess = false ;
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
if ( glDrawBuffers == NULL && ! GLEW_ARB_draw_buffers )
glDrawBuffers = glDrawBuffersARB ;
2009-03-22 11:21:44 +00:00
if ( ! GLEW_ARB_texture_non_power_of_two ) {
2010-01-18 21:11:50 +00:00
WARN_LOG ( VIDEO , "ARB_texture_non_power_of_two not supported." );
2009-03-22 11:21:44 +00:00
}
2009-02-23 07:23:34 +00:00
2009-09-05 05:42:51 +00:00
// Decide frambuffer size
int W = ( int ) OpenGL_GetBackbufferWidth (), H = ( int ) OpenGL_GetBackbufferHeight ();
2010-05-19 03:15:36 +00:00
s_XFB_width = MAX_XFB_WIDTH ;
s_XFB_height = MAX_XFB_HEIGHT ;
TargetRectangle dst_rect ;
ComputeDrawRectangle ( W , H , false , & dst_rect );
xScale = 1.0f ;
yScale = 1.0f ;
if ( ! g_ActiveConfig . bNativeResolution )
{
if ( g_ActiveConfig . b2xResolution )
{
xScale = 2.0f ;
yScale = 2.0f ;
}
else
{
xScale = ( float )( dst_rect . right - dst_rect . left ) / ( float ) s_XFB_width ;
yScale = ( float )( dst_rect . bottom - dst_rect . top ) / ( float ) s_XFB_height ;
}
}
2009-10-22 20:22:50 +00:00
2010-05-19 03:15:36 +00:00
EFBxScale = ceilf ( xScale );
EFByScale = ceilf ( yScale );
2009-06-08 20:07:20 +00:00
2010-05-19 03:15:36 +00:00
m_FrameBufferWidth = EFB_WIDTH * EFBxScale ;
m_FrameBufferHeight = EFB_HEIGHT * EFByScale ;
2009-02-28 19:02:37 +00:00
2009-09-06 15:11:21 +00:00
// Save the custom resolution
2010-05-19 03:15:36 +00:00
m_CustomWidth = W ;
m_CustomHeight = H ;
2009-09-06 15:11:21 +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 ;
2009-02-28 16:33:59 +00:00
2010-06-05 01:38:22 +00:00
if ( GL_REPORT_ERROR () != GL_NO_ERROR )
2009-03-22 11:21:44 +00:00
bSuccess = false ;
2009-06-28 23:35:08 +00:00
// Initialize the FramebufferManager
2009-09-06 15:11:21 +00:00
g_framebufferManager . Init ( m_FrameBufferWidth , m_FrameBufferHeight , s_MSAASamples , s_MSAACoverageSamples );
2009-09-06 13:36:05 +00:00
2009-03-08 19:19:51 +00:00
glDrawBuffer ( GL_COLOR_ATTACHMENT0_EXT );
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
if ( GL_REPORT_ERROR () != GL_NO_ERROR )
2009-02-23 07:23:34 +00:00
bSuccess = false ;
2010-06-05 01:38:22 +00:00
s_pfont = new RasterFont ();
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
// load the effect, find the best profiles (if any)
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBVP1 ) != CG_TRUE ) {
ERROR_LOG ( VIDEO , "arbvp1 not supported" );
return false ;
}
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBFP1 ) != CG_TRUE ) {
ERROR_LOG ( VIDEO , "arbfp1 not supported" );
return false ;
}
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
g_cgvProf = cgGLGetLatestProfile ( CG_GL_VERTEX );
g_cgfProf = cgGLGetLatestProfile ( CG_GL_FRAGMENT );
cgGLSetOptimalOptions ( g_cgvProf );
cgGLSetOptimalOptions ( g_cgfProf );
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
INFO_LOG ( VIDEO , "Max buffer sizes: %d %d" , cgGetProgramBufferMaxSize ( g_cgvProf ), cgGetProgramBufferMaxSize ( g_cgfProf ));
int nenvvertparams , nenvfragparams , naddrregisters [ 2 ];
glGetProgramivARB ( GL_VERTEX_PROGRAM_ARB , GL_MAX_PROGRAM_ENV_PARAMETERS_ARB , ( GLint * ) & nenvvertparams );
glGetProgramivARB ( GL_FRAGMENT_PROGRAM_ARB , GL_MAX_PROGRAM_ENV_PARAMETERS_ARB , ( GLint * ) & nenvfragparams );
glGetProgramivARB ( GL_VERTEX_PROGRAM_ARB , GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB , ( GLint * ) & naddrregisters [ 0 ]);
glGetProgramivARB ( GL_FRAGMENT_PROGRAM_ARB , GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB , ( GLint * ) & naddrregisters [ 1 ]);
DEBUG_LOG ( VIDEO , "Max program env parameters: vert=%d, frag=%d" , nenvvertparams , nenvfragparams );
DEBUG_LOG ( VIDEO , "Max program address register parameters: vert=%d, frag=%d" , naddrregisters [ 0 ], naddrregisters [ 1 ]);
2009-02-23 07:23:34 +00:00
if ( nenvvertparams < 238 )
2010-06-05 01:38:22 +00:00
ERROR_LOG ( VIDEO , "Not enough vertex shader environment constants!!" );
2009-02-23 07:23:34 +00:00
#ifndef _DEBUG
2010-06-05 01:38:22 +00:00
cgGLSetDebugMode ( GL_FALSE );
2009-02-23 07:23:34 +00:00
#endif
2010-06-05 01:38:22 +00:00
glStencilFunc ( GL_ALWAYS , 0 , 0 );
glBlendFunc ( GL_ONE , GL_ONE );
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
glViewport ( 0 , 0 , GetTargetWidth (), GetTargetHeight ()); // Reset The Current Viewport
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
glMatrixMode ( GL_PROJECTION );
glLoadIdentity ();
glMatrixMode ( GL_MODELVIEW );
glLoadIdentity ();
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
glShadeModel ( GL_SMOOTH );
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f );
glClearDepth ( 1.0f );
glEnable ( GL_DEPTH_TEST );
glDisable ( GL_LIGHTING );
glDepthFunc ( GL_LEQUAL );
glPixelStorei ( GL_UNPACK_ALIGNMENT , 4 ); // 4-byte pixel alignment
glDisable ( GL_STENCIL_TEST );
glEnable ( GL_SCISSOR_TEST );
2009-03-05 23:11:13 +00:00
2010-06-05 01:38:22 +00:00
glScissor ( 0 , 0 , GetTargetWidth (), GetTargetHeight ());
glBlendColorEXT ( 0 , 0 , 0 , 0.5f );
glClearDepth ( 1.0f );
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
glMatrixMode ( GL_PROJECTION );
glLoadIdentity ();
glMatrixMode ( GL_MODELVIEW );
glLoadIdentity ();
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
// legacy multitexturing: select texture channel only.
glActiveTexture ( GL_TEXTURE0 );
glClientActiveTexture ( GL_TEXTURE0 );
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE );
2009-02-23 07:23:34 +00:00
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ();
2010-06-05 01:38:22 +00:00
return glGetError () == GL_NO_ERROR && bSuccess ;
2009-02-23 07:23:34 +00:00
}
2009-09-03 19:24:16 +00:00
void Renderer :: Shutdown ( void )
2010-06-05 01:38:22 +00:00
{
2009-09-06 15:11:21 +00:00
g_Config . bRunning = false ;
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ();
2010-06-05 01:38:22 +00:00
delete s_pfont ;
2009-09-03 19:24:16 +00:00
s_pfont = 0 ;
2010-06-05 01:38:22 +00:00
if ( g_cgcontext ) {
cgDestroyContext ( g_cgcontext );
g_cgcontext = 0 ;
2009-09-03 19:24:16 +00:00
}
2010-05-19 03:15:36 +00:00
if ( s_tempScreenshotFramebuffer )
glDeleteFramebuffersEXT ( 1 , & s_tempScreenshotFramebuffer );
2009-09-03 19:24:16 +00:00
s_tempScreenshotFramebuffer = 0 ;
2009-09-03 20:37:35 +00:00
g_framebufferManager . Shutdown ();
2009-09-03 19:24:16 +00:00
#ifdef _WIN32
if ( s_bAVIDumping ) {
AVIDump :: Stop ();
}
#else
if ( f_pFrameDump != NULL ) {
fclose ( f_pFrameDump );
}
#endif
}
2009-02-23 07:23:34 +00:00
2009-09-06 15:11:21 +00:00
// For the OSD menu's live resolution change
bool Renderer :: Allow2x ()
{
if ( GetFrameBufferWidth () >= 1280 && GetFrameBufferHeight () >= 960 )
return true ;
else
return false ;
}
bool Renderer :: AllowCustom ()
{
if ( GetCustomWidth () <= GetFrameBufferWidth () && GetCustomHeight () <= GetFrameBufferHeight ())
return true ;
else
return false ;
}
// Return the framebuffer size
int Renderer :: GetFrameBufferWidth ()
{
return m_FrameBufferWidth ;
}
int Renderer :: GetFrameBufferHeight ()
{
return m_FrameBufferHeight ;
}
// Return the custom resolution
int Renderer :: GetCustomWidth ()
{
return m_CustomWidth ;
}
int Renderer :: GetCustomHeight ()
{
return m_CustomHeight ;
}
// Return the rendering target width and height
2009-02-23 07:23:34 +00:00
int Renderer :: GetTargetWidth ()
{
2010-05-19 03:15:36 +00:00
return m_FrameBufferWidth ;
2009-02-23 07:23:34 +00:00
}
int Renderer :: GetTargetHeight ()
{
2010-05-19 03:15:36 +00:00
return m_FrameBufferHeight ;
2009-02-23 07:23:34 +00:00
}
2009-02-28 16:33:59 +00:00
float Renderer :: GetTargetScaleX ()
{
2010-06-05 01:38:22 +00:00
return EFBxScale ;
2009-02-28 16:33:59 +00:00
}
float Renderer :: GetTargetScaleY ()
{
2010-06-05 01:38:22 +00:00
return EFByScale ;
2009-02-28 16:33:59 +00:00
}
2010-05-19 03:15:36 +00:00
float Renderer :: GetXFBScaleX () { return xScale ; }
float Renderer :: GetXFBScaleY () { return yScale ; }
2009-07-15 00:51:24 +00:00
TargetRectangle Renderer :: ConvertEFBRectangle ( const EFBRectangle & rc )
{
2009-09-03 20:37:35 +00:00
return g_framebufferManager . ConvertEFBRectangle ( rc );
2009-02-23 07:23:34 +00:00
}
2010-05-19 03:15:36 +00:00
2009-09-03 19:24:16 +00:00
void Renderer :: ResetAPIState ()
2009-02-23 07:23:34 +00:00
{
2009-02-28 19:02:37 +00:00
// Gets us to a reasonably sane state where it's possible to do things like
// image copies with textured quads, etc.
2010-06-06 14:44:35 +00:00
glDisable ( GL_VERTEX_PROGRAM_ARB ); // needed by nvidia cards to avoid texture problems
glDisable ( GL_FRAGMENT_PROGRAM_ARB ); // needed by nvidia cards to avoid texture problems
2009-09-26 12:39:12 +00:00
VertexShaderCache :: DisableShader ();
2010-06-05 01:38:22 +00:00
PixelShaderCache :: DisableShader ();
glDisable ( GL_SCISSOR_TEST );
glDisable ( GL_DEPTH_TEST );
glDisable ( GL_CULL_FACE );
glDisable ( GL_BLEND );
glDepthMask ( GL_FALSE );
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE );
2009-02-23 07:23:34 +00:00
}
2009-06-26 08:57:53 +00:00
void UpdateViewport ();
2009-09-03 20:37:35 +00:00
void Renderer :: ReinitView ()
{
}
2009-09-03 19:24:16 +00:00
void Renderer :: RestoreAPIState ()
2009-02-23 07:23:34 +00:00
{
2009-02-28 19:02:37 +00:00
// Gets us back into a more game-like state.
2009-06-26 08:57:53 +00:00
UpdateViewport ();
2010-06-05 01:38:22 +00:00
if ( bpmem . genMode . cullmode > 0 ) glEnable ( GL_CULL_FACE );
if ( bpmem . zmode . testenable ) glEnable ( GL_DEPTH_TEST );
if ( bpmem . zmode . updateenable ) glDepthMask ( GL_TRUE );
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
glEnable ( GL_SCISSOR_TEST );
2009-03-05 23:11:13 +00:00
SetScissorRect ();
2010-06-05 01:38:22 +00:00
SetColorMask ();
2009-02-23 07:23:34 +00:00
SetBlendMode ( true );
2009-03-05 23:11:13 +00:00
2010-06-05 02:15:13 +00:00
glEnable ( GL_VERTEX_PROGRAM_ARB ); // needed by nvidia cards o avoid texture problems
2010-06-06 14:44:35 +00:00
glEnable ( GL_FRAGMENT_PROGRAM_ARB ); // needed by nvidia cards o avoid texture problems
VertexShaderCache :: SetCurrentShader ( 0 );
2010-06-05 01:38:22 +00:00
PixelShaderCache :: SetCurrentShader ( 0 );
2009-02-23 07:23:34 +00:00
}
void Renderer :: SetColorMask ()
{
2009-10-25 02:35:21 +00:00
GLenum ColorMask = ( bpmem . blendmode . colorupdate ) ? GL_TRUE : GL_FALSE ;
GLenum AlphaMask = ( bpmem . blendmode . alphaupdate ) ? GL_TRUE : GL_FALSE ;
glColorMask ( ColorMask , ColorMask , ColorMask , AlphaMask );
2009-02-23 07:23:34 +00:00
}
void Renderer :: SetBlendMode ( bool forceUpdate )
{
// blend mode bit mask
// 0 - blend enable
// 2 - reverse subtract enable (else add)
// 3-5 - srcRGB function
// 6-8 - dstRGB function
2009-06-22 09:31:30 +00:00
u32 newval = bpmem . blendmode . subtract << 2 ;
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
if ( bpmem . blendmode . subtract ) {
newval |= 0x0049 ; // enable blending src 1 dst 1
} else if ( bpmem . blendmode . blendenable ) {
2009-03-16 02:47:48 +00:00
newval |= 1 ; // enable blending
2009-06-22 09:31:30 +00:00
newval |= bpmem . blendmode . srcfactor << 3 ;
newval |= bpmem . blendmode . dstfactor << 6 ;
2009-02-23 07:23:34 +00:00
}
2009-03-16 02:47:48 +00:00
2009-02-23 07:23:34 +00:00
u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode ;
if ( changes & 1 ) {
2010-06-05 01:38:22 +00:00
// blend enable change
2009-03-05 23:11:13 +00:00
( newval & 1 ) ? glEnable ( GL_BLEND ) : glDisable ( GL_BLEND );
2009-02-23 07:23:34 +00:00
}
2010-06-05 01:38:22 +00:00
if ( changes & 4 ) {
2009-03-16 02:47:48 +00:00
// subtract enable change
glBlendEquation ( newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD );
2009-02-23 07:23:34 +00:00
}
2009-03-16 02:47:48 +00:00
if ( changes & 0x1F8 ) {
// blend RGB change
glBlendFunc ( glSrcFactors [( newval >> 3 ) & 7 ], glDestFactors [( newval >> 6 ) & 7 ]);
2009-02-23 07:23:34 +00:00
}
s_blendMode = newval ;
}
2009-07-15 00:51:24 +00:00
u32 Renderer :: AccessEFB ( EFBAccessType type , int x , int y )
{
2010-01-07 20:01:41 +00:00
if ( ! g_ActiveConfig . bEFBAccessEnable )
return 0 ;
2009-07-15 00:51:24 +00:00
// Get the rectangular target region covered by the EFB pixel.
EFBRectangle efbPixelRc ;
efbPixelRc . left = x ;
efbPixelRc . top = y ;
efbPixelRc . right = x + 1 ;
efbPixelRc . bottom = y + 1 ;
TargetRectangle targetPixelRc = Renderer :: ConvertEFBRectangle ( efbPixelRc );
2009-08-22 13:22:35 +00:00
// TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
2009-07-15 00:51:24 +00:00
switch ( type )
{
case PEEK_Z :
{
if ( s_MSAASamples > 1 )
{
2009-07-16 09:06:16 +00:00
// Resolve our rectangle.
2009-09-03 20:37:35 +00:00
g_framebufferManager . GetEFBDepthTexture ( efbPixelRc );
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetResolvedFramebuffer ());
2009-07-15 00:51:24 +00:00
}
// Sample from the center of the target region.
int srcX = ( targetPixelRc . left + targetPixelRc . right ) / 2 ;
int srcY = ( targetPixelRc . top + targetPixelRc . bottom ) / 2 ;
2009-07-15 15:09:20 +00:00
u32 z = 0 ;
2009-07-15 00:51:24 +00:00
glReadPixels ( srcX , srcY , 1 , 1 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , & z );
GL_REPORT_ERRORD ();
// Scale the 32-bit value returned by glReadPixels to a 24-bit
// value (GC uses a 24-bit Z-buffer).
2009-08-25 18:30:15 +00:00
// TODO: in RE0 this value is often off by one, which causes lighting to disappear
2009-07-15 00:51:24 +00:00
return z >> 8 ;
}
case POKE_Z :
// TODO: Implement
break ;
2009-08-22 13:22:35 +00:00
case PEEK_COLOR : // GXPeekARGB
2009-07-16 09:06:16 +00:00
{
2009-08-22 13:22:35 +00:00
// 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
2010-06-05 01:38:22 +00:00
// determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
2009-08-22 13:22:35 +00:00
// Wind Waker is also using it for the pictograph to determine the color of each pixel
2009-07-16 22:45:18 +00:00
2009-07-16 09:06:16 +00:00
if ( s_MSAASamples > 1 )
{
// Resolve our rectangle.
2009-09-03 20:37:35 +00:00
g_framebufferManager . GetEFBColorTexture ( efbPixelRc );
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetResolvedFramebuffer ());
2009-07-16 09:06:16 +00:00
}
2009-07-15 15:09:20 +00:00
2009-07-16 09:06:16 +00:00
// Sample from the center of the target region.
int srcX = ( targetPixelRc . left + targetPixelRc . right ) / 2 ;
int srcY = ( targetPixelRc . top + targetPixelRc . bottom ) / 2 ;
2009-07-15 15:09:20 +00:00
2009-08-22 13:22:35 +00:00
// Read back pixel in BGRA format, then byteswap to get GameCube's ARGB Format.
2009-07-16 09:06:16 +00:00
u32 color = 0 ;
2009-08-22 13:22:35 +00:00
glReadPixels ( srcX , srcY , 1 , 1 , GL_BGRA , GL_UNSIGNED_INT_8_8_8_8_REV , & color );
2009-07-16 09:06:16 +00:00
GL_REPORT_ERRORD ();
2009-07-15 15:09:20 +00:00
2009-08-22 13:22:35 +00:00
return color ;
2009-07-16 09:06:16 +00:00
}
2009-07-15 00:51:24 +00:00
case POKE_COLOR :
// 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 ;
}
return 0 ;
}
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
bool Renderer :: SetScissorRect ()
{
2010-06-05 01:38:22 +00:00
int xoff = bpmem . scissorOffset . x * 2 - 342 ;
int yoff = bpmem . scissorOffset . y * 2 - 342 ;
float rc_left = ( float ) bpmem . scissorTL . x - xoff - 342 ; // left = 0
if ( rc_left < 0 ) rc_left = 0 ;
2009-02-23 07:23:34 +00:00
2009-06-22 09:31:30 +00:00
float rc_top = ( float ) bpmem . scissorTL . y - yoff - 342 ; // right = 0
2010-06-05 01:38:22 +00:00
if ( rc_top < 0 ) rc_top = 0 ;
2009-06-22 09:31:30 +00:00
float rc_right = ( float ) bpmem . scissorBR . x - xoff - 341 ; // right = 640
2010-05-19 03:15:36 +00:00
if ( rc_right > EFB_WIDTH ) rc_right = EFB_WIDTH ;
2009-02-23 07:23:34 +00:00
2009-06-22 09:31:30 +00:00
float rc_bottom = ( float ) bpmem . scissorBR . y - yoff - 341 ; // bottom = 480
2010-06-05 01:38:22 +00:00
if ( rc_bottom > EFB_HEIGHT ) rc_bottom = EFB_HEIGHT ;
2009-02-23 07:23:34 +00:00
2010-05-19 03:15:36 +00:00
if ( rc_left > rc_right )
2009-11-23 14:08:08 +00:00
{
int temp = rc_right ;
rc_right = rc_left ;
rc_left = temp ;
}
if ( rc_top > rc_bottom )
{
int temp = rc_bottom ;
rc_bottom = rc_top ;
rc_top = temp ;
}
2009-02-23 07:23:34 +00:00
2010-05-19 03:15:36 +00:00
2009-02-23 07:23:34 +00:00
// Check that the coordinates are good
2010-06-05 01:38:22 +00:00
if ( rc_right >= rc_left && rc_bottom >= rc_top )
2009-02-23 07:23:34 +00:00
{
2010-05-19 03:15:36 +00:00
glScissor (
( int )( rc_left * EFBxScale ), // x = 0 for example
( int )(( EFB_HEIGHT - rc_bottom ) * EFByScale ), // y = 0 for example
( int )(( rc_right - rc_left ) * EFBxScale ), // width = 640 for example
( int )(( rc_bottom - rc_top ) * EFByScale ) // height = 480 for example
2009-02-23 07:23:34 +00:00
);
2010-06-05 01:38:22 +00:00
return true ;
}
2010-05-19 03:15:36 +00:00
else
{
glScissor (
0 ,
0 ,
Renderer :: GetTargetWidth (),
2010-06-05 01:38:22 +00:00
Renderer :: GetTargetHeight ()
);
2010-05-19 03:15:36 +00:00
}
2010-06-05 01:38:22 +00:00
return false ;
2009-02-23 07:23:34 +00:00
}
2009-07-15 00:51:24 +00:00
void Renderer :: ClearScreen ( const EFBRectangle & rc , bool colorEnable , bool alphaEnable , bool zEnable , u32 color , u32 z )
{
// Update the view port for clearing the picture
glViewport ( 0 , 0 , Renderer :: GetTargetWidth (), Renderer :: GetTargetHeight ());
TargetRectangle targetRc = Renderer :: ConvertEFBRectangle ( rc );
2010-06-05 01:38:22 +00:00
// Always set the scissor in case it was set by the game and has not been reset
2009-07-15 00:51:24 +00:00
glScissor ( targetRc . left , targetRc . bottom , targetRc . GetWidth (), targetRc . GetHeight ());
2010-06-05 01:38:22 +00:00
VertexShaderManager :: SetViewportChanged ();
2009-07-15 00:51:24 +00:00
GLbitfield bits = 0 ;
if ( colorEnable )
{
bits |= GL_COLOR_BUFFER_BIT ;
glClearColor (
(( color >> 16 ) & 0xFF ) / 255.0f ,
(( color >> 8 ) & 0xFF ) / 255.0f ,
( color & 0xFF ) / 255.0f ,
( alphaEnable ? (( color >> 24 ) & 0xFF ) / 255.0f : 1.0f )
);
}
if ( zEnable )
{
bits |= GL_DEPTH_BUFFER_BIT ;
glClearDepth (( z & 0xFFFFFF ) / float ( 0xFFFFFF ));
}
glDrawBuffer ( GL_COLOR_ATTACHMENT0_EXT );
glClear ( bits );
2010-05-19 03:15:36 +00:00
SetScissorRect ();
2009-07-15 00:51:24 +00:00
}
2010-03-25 22:01:33 +00:00
static bool XFBWrited = false ;
2009-07-15 00:51:24 +00:00
void Renderer :: RenderToXFB ( u32 xfbAddr , u32 fbWidth , u32 fbHeight , const EFBRectangle & sourceRc )
2009-06-26 08:57:53 +00:00
{
2010-05-14 21:47:16 +00:00
if ( ! fbWidth || ! fbHeight )
return ;
2009-08-08 01:39:56 +00:00
s_skipSwap = g_bSkipCurrentFrame ;
2010-04-04 13:19:03 +00:00
VideoFifo_CheckEFBAccess ();
2010-05-14 21:47:16 +00:00
VideoFifo_CheckSwapRequestAt ( xfbAddr , fbWidth , fbHeight );
2009-09-03 20:37:35 +00:00
g_framebufferManager . CopyToXFB ( xfbAddr , fbWidth , fbHeight , sourceRc );
2010-03-25 22:01:33 +00:00
XFBWrited = true ;
2009-08-04 22:36:50 +00:00
// XXX: Without the VI, how would we know what kind of field this is? So
// just use progressive.
2009-09-13 08:21:35 +00:00
if ( ! g_ActiveConfig . bUseXFB )
2009-08-31 17:47:17 +00:00
{
2009-08-25 18:30:15 +00:00
Renderer :: Swap ( xfbAddr , FIELD_PROGRESSIVE , fbWidth , fbHeight );
2010-03-10 06:45:13 +00:00
Common :: AtomicStoreRelease ( s_swapRequested , FALSE );
2009-08-31 17:47:17 +00:00
}
2009-06-26 08:57:53 +00:00
}
2009-06-07 12:06:15 +00:00
2009-06-29 07:30:48 +00:00
// This function has the final picture. We adjust the aspect ratio here.
2009-07-11 02:34:16 +00:00
void Renderer :: Swap ( u32 xfbAddr , FieldType field , u32 fbWidth , u32 fbHeight )
2009-02-28 16:33:59 +00:00
{
2010-05-14 21:47:16 +00:00
if ( g_bSkipCurrentFrame || ( ! XFBWrited && ! g_ActiveConfig . bUseRealXFB ) || ! fbWidth || ! fbHeight )
2010-01-28 14:37:03 +00:00
{
g_VideoInitialize . pCopiedToXFB ( false );
2009-08-08 01:39:56 +00:00
return ;
2010-06-05 01:38:22 +00:00
}
2010-04-14 13:57:16 +00:00
if ( field == FIELD_LOWER ) xfbAddr -= fbWidth * 2 ;
2010-03-10 06:45:13 +00:00
u32 xfbCount = 0 ;
const XFBSource ** xfbSourceList = g_framebufferManager . GetXFBSource ( xfbAddr , fbWidth , fbHeight , xfbCount );
if ( ! xfbSourceList )
2009-06-29 07:30:48 +00:00
{
2010-03-28 23:51:32 +00:00
g_VideoInitialize . pCopiedToXFB ( false );
2009-06-29 07:30:48 +00:00
WARN_LOG ( VIDEO , "Failed to get video for this frame" );
return ;
}
2010-06-05 01:38:22 +00:00
DVSTARTPROFILE ();
2009-02-23 07:23:34 +00:00
2010-06-05 01:38:22 +00:00
ResetAPIState ();
2009-02-23 07:23:34 +00:00
2009-07-15 00:51:24 +00:00
TargetRectangle back_rc ;
2010-05-19 03:15:36 +00:00
ComputeDrawRectangle ( m_CustomWidth , m_CustomHeight , true , & back_rc );
2009-02-28 16:33:59 +00:00
2009-06-08 18:34:24 +00:00
// Make sure that the wireframe setting doesn't screw up the screen copy.
2009-03-22 13:25:05 +00:00
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL );
2009-06-26 08:57:53 +00:00
// Textured triangles are necessary because of post-processing shaders
// Disable all other stages
for ( int i = 1 ; i < 8 ; ++ i )
TextureMngr :: DisableStage ( i );
// Update GLViewPort
2009-07-15 00:51:24 +00:00
glViewport ( back_rc . left , back_rc . bottom , back_rc . GetWidth (), back_rc . GetHeight ());
2009-06-26 08:57:53 +00:00
GL_REPORT_ERRORD ();
// Copy the framebuffer to screen.
// Render to the real buffer now.
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ); // switch to the window backbuffer
// Texture map s_xfbTexture onto the main buffer
glActiveTexture ( GL_TEXTURE0 );
glEnable ( GL_TEXTURE_RECTANGLE_ARB );
// Use linear filtering.
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER , GL_LINEAR );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER , GL_LINEAR );
2010-06-05 01:38:22 +00:00
// We must call ApplyShader here even if no post proc is selected - it takes
2009-06-26 08:57:53 +00:00
// care of disabling it in that case. It returns false in case of no post processing.
2010-03-10 06:45:13 +00:00
bool applyShader = PostProcessing :: ApplyShader ();
2010-04-12 01:33:10 +00:00
const XFBSource * xfbSource = NULL ;
2010-03-10 06:45:13 +00:00
// draw each xfb source
for ( u32 i = 0 ; i < xfbCount ; ++ i )
2009-03-08 19:19:51 +00:00
{
2010-06-05 01:38:22 +00:00
xfbSource = xfbSourceList [ i ];
2010-03-10 06:45:13 +00:00
TargetRectangle sourceRc ;
if ( g_ActiveConfig . bAutoScale || g_ActiveConfig . bUseXFB )
{
sourceRc = xfbSource -> sourceRc ;
}
else
{
sourceRc . left = 0 ;
sourceRc . top = xfbSource -> texHeight ;
sourceRc . right = xfbSource -> texWidth ;
sourceRc . bottom = 0 ;
}
MathUtil :: Rectangle < float > drawRc ;
if ( g_ActiveConfig . bUseXFB && ! g_ActiveConfig . bUseRealXFB )
{
// use virtual xfb with offset
int xfbHeight = xfbSource -> srcHeight ;
int xfbWidth = xfbSource -> srcWidth ;
int hOffset = (( s32 ) xfbSource -> srcAddr - ( s32 ) xfbAddr ) / (( s32 ) fbWidth * 2 );
drawRc . top = 1.0f - ( 2.0f * ( hOffset ) / ( float ) fbHeight );
drawRc . bottom = 1.0f - ( 2.0f * ( hOffset + xfbHeight ) / ( float ) fbHeight );
drawRc . left = - ( xfbWidth / ( float ) fbWidth );
drawRc . right = ( xfbWidth / ( float ) fbWidth );
if ( ! g_ActiveConfig . bAutoScale )
{
// scale draw area for a 1 to 1 pixel mapping with the draw target
float vScale = ( float ) fbHeight / ( float ) back_rc . GetHeight ();
float hScale = ( float ) fbWidth / ( float ) back_rc . GetWidth ();
drawRc . top *= vScale ;
drawRc . bottom *= vScale ;
drawRc . left *= hScale ;
drawRc . right *= hScale ;
}
}
else
{
drawRc . top = 1 ;
drawRc . bottom = - 1 ;
drawRc . left = - 1 ;
drawRc . right = 1 ;
}
// Tell the OSD Menu about the current internal resolution
OSDInternalW = xfbSource -> sourceRc . GetWidth (); OSDInternalH = xfbSource -> sourceRc . GetHeight ();
// Texture map xfbSource->texture onto the main buffer
glBindTexture ( GL_TEXTURE_RECTANGLE_ARB , xfbSource -> texture );
2010-06-05 01:38:22 +00:00
// We must call ApplyShader here even if no post proc is selected - it takes
2010-03-10 06:45:13 +00:00
// care of disabling it in that case. It returns false in case of no post processing.
if ( applyShader )
{
glBegin ( GL_QUADS );
glTexCoord2f ( sourceRc . left , sourceRc . bottom ); glMultiTexCoord2fARB ( GL_TEXTURE1 , 0 , 0 ); glVertex2f ( drawRc . left , drawRc . bottom );
glTexCoord2f ( sourceRc . left , sourceRc . top ); glMultiTexCoord2fARB ( GL_TEXTURE1 , 0 , 1 ); glVertex2f ( drawRc . left , drawRc . top );
glTexCoord2f ( sourceRc . right , sourceRc . top ); glMultiTexCoord2fARB ( GL_TEXTURE1 , 1 , 1 ); glVertex2f ( drawRc . right , drawRc . top );
glTexCoord2f ( sourceRc . right , sourceRc . bottom ); glMultiTexCoord2fARB ( GL_TEXTURE1 , 1 , 0 ); glVertex2f ( drawRc . right , drawRc . bottom );
glEnd ();
2010-06-05 01:38:22 +00:00
PixelShaderCache :: DisableShader ();
2010-03-10 06:45:13 +00:00
}
else
{
glBegin ( GL_QUADS );
glTexCoord2f ( sourceRc . left , sourceRc . bottom ); glVertex2f ( drawRc . left , drawRc . bottom );
2010-06-05 01:38:22 +00:00
glTexCoord2f ( sourceRc . left , sourceRc . top ); glVertex2f ( drawRc . left , drawRc . top );
glTexCoord2f ( sourceRc . right , sourceRc . top ); glVertex2f ( drawRc . right , drawRc . top );
2010-03-10 06:45:13 +00:00
glTexCoord2f ( sourceRc . right , sourceRc . bottom ); glVertex2f ( drawRc . right , drawRc . bottom );
glEnd ();
}
GL_REPORT_ERRORD ();
2009-03-08 19:19:51 +00:00
}
2009-02-23 07:23:34 +00:00
2009-06-26 08:57:53 +00:00
glBindTexture ( GL_TEXTURE_RECTANGLE_ARB , 0 );
TextureMngr :: DisableStage ( 0 );
2009-03-22 13:25:05 +00:00
// Wireframe
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bWireFrame )
2009-03-22 13:25:05 +00:00
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE );
2009-06-08 00:44:48 +00:00
// Save screenshot
if ( s_bScreenshot )
2009-06-07 11:51:53 +00:00
{
2009-06-29 20:54:47 +00:00
if ( ! s_tempScreenshotFramebuffer )
glGenFramebuffersEXT ( 1 , & s_tempScreenshotFramebuffer );
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , s_tempScreenshotFramebuffer );
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , xfbSource -> texture , 0 );
2009-06-07 11:51:53 +00:00
2009-06-08 00:44:48 +00:00
s_criticalScreenshot . Enter ();
2009-06-07 11:51:53 +00:00
// Save screenshot
2010-03-10 06:45:13 +00:00
SaveRenderTarget ( s_sScreenshotName . c_str (), xfbSource -> sourceRc . GetWidth (), xfbSource -> sourceRc . GetHeight ());
2009-06-07 11:51:53 +00:00
// Reset settings
s_sScreenshotName = "" ;
s_bScreenshot = false ;
s_criticalScreenshot . Leave ();
2009-06-29 20:54:47 +00:00
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , 0 , 0 );
2009-09-03 20:37:35 +00:00
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetEFBFramebuffer ());
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
#ifdef _WIN32
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bDumpFrames )
2009-06-08 10:16:08 +00:00
{
2009-06-29 20:54:47 +00:00
if ( ! s_tempScreenshotFramebuffer )
glGenFramebuffersEXT ( 1 , & s_tempScreenshotFramebuffer );
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , s_tempScreenshotFramebuffer );
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , xfbSource -> texture , 0 );
2009-06-08 10:16:08 +00:00
2009-03-28 21:07:16 +00:00
s_criticalScreenshot . Enter ();
2009-06-29 20:54:47 +00:00
int w = xfbSource -> sourceRc . GetWidth ();
int h = xfbSource -> sourceRc . GetHeight ();
2009-07-29 00:49:12 +00:00
2009-03-28 21:07:16 +00:00
u8 * data = ( u8 * ) malloc ( 3 * w * h );
glPixelStorei ( GL_PACK_ALIGNMENT , 1 );
2010-03-10 06:45:13 +00:00
glReadPixels ( 0 , Renderer :: GetTargetHeight () - h , w , h , GL_BGR , GL_UNSIGNED_BYTE , data );
2010-06-05 01:38:22 +00:00
if ( glGetError () == GL_NO_ERROR && w > 0 && h > 0 )
2009-04-03 14:35:49 +00:00
{
2010-06-05 01:38:22 +00:00
if ( ! s_bLastFrameDumped )
2009-04-03 14:35:49 +00:00
{
2009-09-06 19:30:24 +00:00
s_bAVIDumping = AVIDump :: Start ( EmuWindow :: GetParentWnd (), w , h );
2009-04-03 14:35:49 +00:00
if ( ! s_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-02-02 21:56:29 +00:00
"Dumping Frames to \" %sframedump0.avi \" (%dx%d RGB24)" , File :: GetUserPath ( D_DUMPFRAMES_IDX ), w , h ). c_str (), 2000 );
2009-03-28 21:07:16 +00:00
}
}
2010-06-05 01:38:22 +00:00
if ( s_bAVIDumping )
2009-03-28 21:07:16 +00:00
AVIDump :: AddFrame (( char * ) data );
2009-04-03 14:35:49 +00:00
2009-03-28 21:07:16 +00:00
s_bLastFrameDumped = true ;
}
2009-06-08 10:16:08 +00:00
else
{
NOTICE_LOG ( VIDEO , "Error reading framebuffer" );
}
2009-03-28 21:07:16 +00:00
free ( data );
s_criticalScreenshot . Leave ();
2009-06-29 20:54:47 +00:00
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , 0 , 0 );
2009-09-03 20:37:35 +00:00
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetEFBFramebuffer ());
2010-06-05 01:38:22 +00:00
}
else
2009-04-03 14:35:49 +00:00
{
2010-06-05 01:38:22 +00:00
if ( s_bLastFrameDumped && s_bAVIDumping )
2009-04-03 14:35:49 +00:00
{
2009-03-28 21:07:16 +00:00
AVIDump :: Stop ();
s_bAVIDumping = false ;
2009-06-08 10:16:08 +00:00
OSD :: AddMessage ( "Stop dumping frames to AVI" , 2000 );
2009-03-28 21:07:16 +00:00
}
s_bLastFrameDumped = false ;
}
#else
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bDumpFrames ) {
2009-03-28 21:07:16 +00:00
s_criticalScreenshot . Enter ();
char movie_file_name [ 255 ];
int w = OpenGL_GetBackbufferWidth ();
int h = OpenGL_GetBackbufferHeight ();
u8 * data = ( u8 * ) malloc ( 3 * w * h );
glPixelStorei ( GL_PACK_ALIGNMENT , 1 );
2009-07-29 00:49:12 +00:00
glReadPixels ( 0 , Renderer :: GetTargetHeight () - h , w , h , GL_RGB , GL_UNSIGNED_BYTE , data );
2009-03-28 21:07:16 +00:00
if ( glGetError () == GL_NO_ERROR ) {
if ( ! s_bLastFrameDumped ) {
2010-02-02 21:56:29 +00:00
sprintf ( movie_file_name , "%sframedump.raw" , File :: GetUserPath ( D_DUMPFRAMES_IDX ));
2009-03-28 21:07:16 +00:00
f_pFrameDump = fopen ( movie_file_name , "wb" );
if ( f_pFrameDump == NULL ) {
PanicAlert ( "Error opening framedump.raw for writing." );
} else {
char msg [ 255 ];
sprintf ( msg , "Dumping Frames to \" %s \" (%dx%d RGB24)" , movie_file_name , w , h );
OSD :: AddMessage ( msg , 2000 );
}
}
if ( f_pFrameDump != NULL ) {
FlipImageData ( data , w , h );
fwrite ( data , w * 3 , h , f_pFrameDump );
fflush ( f_pFrameDump );
}
s_bLastFrameDumped = true ;
}
free ( data );
s_criticalScreenshot . Leave ();
} else {
2009-09-13 10:18:01 +00:00
if ( s_bLastFrameDumped && f_pFrameDump != NULL ) {
2009-03-28 21:07:16 +00:00
fclose ( f_pFrameDump );
f_pFrameDump = NULL ;
}
s_bLastFrameDumped = false ;
}
#endif
2010-05-19 03:15:36 +00:00
OpenGL_Update (); // just updates the render window position and the backbuffer size
bool xfbchanged = false ;
if ( s_XFB_width != fbWidth || s_XFB_height != fbHeight )
{
xfbchanged = true ;
s_XFB_width = fbWidth ;
s_XFB_height = fbHeight ;
if ( s_XFB_width < 1 ) s_XFB_width = MAX_XFB_WIDTH ;
if ( s_XFB_width > MAX_XFB_WIDTH ) s_XFB_width = MAX_XFB_WIDTH ;
if ( s_XFB_height < 1 ) s_XFB_height = MAX_XFB_HEIGHT ;
if ( s_XFB_height > MAX_XFB_HEIGHT ) s_XFB_height = MAX_XFB_HEIGHT ;
}
bool WindowResized = false ;
int W = ( int ) OpenGL_GetBackbufferWidth (), H = ( int ) OpenGL_GetBackbufferHeight ();
if ( W != m_CustomWidth || H != m_CustomHeight )
{
WindowResized = true ;
m_CustomWidth = W ;
m_CustomHeight = H ;
}
if ( xfbchanged || WindowResized )
2010-06-05 01:38:22 +00:00
{
2010-05-19 03:15:36 +00:00
TargetRectangle dst_rect ;
ComputeDrawRectangle ( m_CustomWidth , m_CustomHeight , false , & dst_rect );
xScale = 1.0f ;
yScale = 1.0f ;
if ( ! g_ActiveConfig . bNativeResolution )
{
if ( g_ActiveConfig . b2xResolution )
{
xScale = 2.0f ;
yScale = 2.0f ;
}
else
{
xScale = ( float )( dst_rect . right - dst_rect . left ) / ( float ) s_XFB_width ;
yScale = ( float )( dst_rect . bottom - dst_rect . top ) / ( float ) s_XFB_height ;
}
}
EFBxScale = ceilf ( xScale );
EFByScale = ceilf ( yScale );
int m_newFrameBufferWidth = EFB_WIDTH * EFBxScale ;
int m_newFrameBufferHeight = EFB_HEIGHT * EFByScale ;
if ( m_newFrameBufferWidth != m_FrameBufferWidth || m_newFrameBufferHeight != m_FrameBufferHeight )
{
m_FrameBufferWidth = m_newFrameBufferWidth ;
m_FrameBufferHeight = m_newFrameBufferHeight ;
g_framebufferManager . Shutdown ();
g_framebufferManager . Init ( m_FrameBufferWidth , m_FrameBufferHeight , s_MSAASamples , s_MSAACoverageSamples );
glDrawBuffer ( GL_COLOR_ATTACHMENT0_EXT );
}
}
2009-02-23 07:23:34 +00:00
// Place messages on the picture, then copy it to the screen
2009-06-07 12:06:15 +00:00
// ---------------------------------------------------------------------
// Count FPS.
2009-09-08 16:07:13 +00:00
// -------------
2009-06-07 12:06:15 +00:00
static int fpscount = 0 ;
2010-06-05 01:38:22 +00:00
static unsigned long lasttime ;
++ fpscount ;
if ( Common :: Timer :: GetTimeMs () - lasttime > 1000 )
{
lasttime = Common :: Timer :: GetTimeMs ();
s_fps = fpscount - 1 ;
fpscount = 0 ;
}
2009-06-07 12:06:15 +00:00
// ---------------------------------------------------------------------
2010-06-05 01:38:22 +00:00
GL_REPORT_ERRORD ();
2009-10-25 02:35:21 +00:00
2009-06-07 12:06:15 +00:00
DrawDebugText ();
2010-06-05 01:38:22 +00:00
GL_REPORT_ERRORD ();
2009-06-13 22:08:01 +00:00
2009-09-03 20:37:35 +00:00
// Get the status of the Blend mode
GLboolean blend_enabled = glIsEnabled ( GL_BLEND );
glDisable ( GL_BLEND );
2009-06-07 12:06:15 +00:00
OSD :: DrawMessages ();
2009-09-03 20:37:35 +00:00
if ( blend_enabled )
glEnable ( GL_BLEND );
2010-06-05 01:38:22 +00:00
GL_REPORT_ERRORD ();
2009-06-07 12:06:15 +00:00
#if defined(DVPROFILE)
2010-06-05 01:38:22 +00:00
if ( g_bWriteProfile ) {
//g_bWriteProfile = 0;
static int framenum = 0 ;
const int UPDATE_FRAMES = 8 ;
if ( ++ framenum >= UPDATE_FRAMES ) {
DVProfWrite ( "prof.txt" , UPDATE_FRAMES );
DVProfClear ();
framenum = 0 ;
}
}
2009-06-07 12:06:15 +00:00
#endif
2010-06-05 01:38:22 +00:00
// Copy the rendered frame to the real window
2009-06-07 12:06:15 +00:00
OpenGL_SwapBuffers ();
2010-06-05 01:38: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
2009-10-21 00:01:07 +00:00
glClearColor ( 0 , 0 , 0 , 0 );
glClear ( GL_COLOR_BUFFER_BIT );
2009-06-07 12:06:15 +00:00
2009-08-08 01:39:56 +00:00
GL_REPORT_ERRORD ();
2009-06-07 12:06:15 +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-06-05 01:38:22 +00:00
TextureMngr :: ProgressiveCleanup ();
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-06-05 01:38:22 +00:00
// New frame
stats . ResetFrame ();
2009-06-07 12:06:15 +00:00
// Render to the framebuffer.
2009-09-03 20:37:35 +00:00
g_framebufferManager . SetFramebuffer ( 0 );
2009-06-07 12:06:15 +00:00
GL_REPORT_ERRORD ();
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-02-08 23:23:04 +00:00
bool last_copy_efb_to_Texture = g_ActiveConfig . bCopyEFBToTexture ;
2009-09-13 17:46:33 +00:00
UpdateActiveConfig ();
2010-02-08 23:23:04 +00:00
if ( last_copy_efb_to_Texture != g_ActiveConfig . bCopyEFBToTexture )
2009-09-13 17:46:33 +00:00
TextureMngr :: ClearRenderTargets ();
// For testing zbuffer targets.
2010-06-05 01:38:22 +00:00
// Renderer::SetZBufferRender();
// SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget, GetTargetWidth(), GetTargetHeight());
2010-03-25 22:01:33 +00:00
XFBWrited = false ;
2010-05-14 21:47:16 +00:00
g_VideoInitialize . pCopiedToXFB ( true );
2009-09-13 17:46:33 +00:00
}
2009-06-07 12:06:15 +00:00
// Create On-Screen-Messages
2009-02-28 16:33:59 +00:00
void Renderer :: DrawDebugText ()
2009-02-23 07:23:34 +00:00
{
2009-03-08 19:19:51 +00:00
// Reset viewport for drawing text
glViewport ( 0 , 0 , OpenGL_GetBackbufferWidth (), OpenGL_GetBackbufferHeight ());
2009-02-28 16:33:59 +00:00
// Draw various messages on the screen, like FPS, statistics, etc.
2009-02-23 07:23:34 +00:00
char debugtext_buffer [ 8192 ];
char * p = debugtext_buffer ;
p [ 0 ] = 0 ;
2009-04-03 14:35:49 +00:00
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bShowFPS )
2009-02-23 07:23:34 +00:00
p += sprintf ( p , "FPS: %d \n " , s_fps );
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bShowEFBCopyRegions )
2009-03-16 07:54:44 +00:00
{
2009-03-17 06:04:57 +00:00
// Store Line Size
2010-06-05 01:38:22 +00:00
GLfloat lSize ;
2009-03-21 16:04:44 +00:00
glGetFloatv ( GL_LINE_WIDTH , & lSize );
2009-03-17 06:04:57 +00:00
// Set Line Size
2010-06-05 01:38:22 +00:00
glLineWidth ( 3.0f );
2009-03-16 07:54:44 +00:00
glBegin ( GL_LINES );
2009-03-17 06:04:57 +00:00
// Draw EFB copy regions rectangles
2009-07-15 00:51:24 +00:00
for ( std :: vector < EFBRectangle >:: const_iterator it = stats . efb_regions . begin (); it != stats . efb_regions . end (); ++ it )
2009-03-16 07:54:44 +00:00
{
2009-07-28 05:02:47 +00:00
GLfloat halfWidth = EFB_WIDTH / 2.0f ;
2010-06-05 01:38:22 +00:00
GLfloat halfHeight = EFB_HEIGHT / 2.0f ;
GLfloat x = ( GLfloat ) - 1.0f + (( GLfloat ) it -> left / halfWidth );
2009-03-21 16:04:44 +00:00
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-03-16 07:54:44 +00:00
2009-03-17 06:04:57 +00:00
// Draw shadow of rect
2009-03-16 07:54:44 +00:00
glColor3f ( 0.0f , 0.0f , 0.0f );
2009-04-03 21:32:10 +00:00
glVertex2f ( x , y - 0.01 ); glVertex2f ( x2 , y - 0.01 );
glVertex2f ( x , y2 - 0.01 ); glVertex2f ( x2 , y2 - 0.01 );
glVertex2f ( x + 0.005 , y ); glVertex2f ( x + 0.005 , y2 );
glVertex2f ( x2 + 0.005 , y ); glVertex2f ( x2 + 0.005 , y2 );
2009-03-16 07:54:44 +00:00
2009-03-17 06:04:57 +00:00
// Draw rect
2009-03-16 07:54:44 +00:00
glColor3f ( 0.0f , 1.0f , 1.0f );
2009-04-03 21:32:10 +00:00
glVertex2f ( x , y ); glVertex2f ( x2 , y );
glVertex2f ( x , y2 ); glVertex2f ( x2 , y2 );
glVertex2f ( x , y ); glVertex2f ( x , y2 );
glVertex2f ( x2 , y ); glVertex2f ( x2 , y2 );
2009-03-16 07:54:44 +00:00
}
glEnd ();
2009-03-17 06:04:57 +00:00
// Restore Line Size
2009-03-21 16:04:44 +00:00
glLineWidth ( lSize );
2009-03-17 06:04:57 +00:00
// Clear stored regions
2009-03-16 07:54:44 +00:00
stats . efb_regions . clear ();
}
2010-06-05 01:38:22 +00:00
if ( g_ActiveConfig . bOverlayStats )
2009-03-16 07:54:44 +00:00
{
2009-09-13 08:21:35 +00:00
p = Statistics :: ToString ( p );
2010-06-05 01:38:22 +00:00
}
2009-02-23 07:23:34 +00:00
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bOverlayProjStats )
2009-02-23 07:23:34 +00:00
{
2009-09-13 08:21:35 +00:00
p = Statistics :: ToStringProj ( p );
2009-02-23 07:23:34 +00:00
}
// Render a shadow, and then the text.
2009-09-13 08:21:35 +00:00
if ( p != debugtext_buffer )
{
Renderer :: RenderText ( debugtext_buffer , 21 , 21 , 0xDD000000 );
Renderer :: RenderText ( debugtext_buffer , 20 , 20 , 0xFF00FFFF );
}
2009-06-08 02:48:38 +00:00
// OSD Menu messages
2009-10-22 20:22:50 +00:00
if ( g_ActiveConfig . bOSDHotKey )
2009-06-08 02:48:38 +00:00
{
2009-10-22 20:22:50 +00:00
if ( OSDChoice > 0 )
{
2010-01-21 21:27:52 +00:00
OSDTime = Common :: Timer :: GetTimeMs () + 3000 ;
2009-10-22 20:22:50 +00:00
OSDChoice = - OSDChoice ;
}
2010-01-21 21:27:52 +00:00
if (( u32 ) OSDTime > Common :: Timer :: GetTimeMs ())
2009-10-22 20:22:50 +00:00
{
std :: string T1 = "" , T2 = "" ;
std :: vector < std :: string > T0 ;
2009-06-08 02:48:38 +00:00
2009-10-22 20:22:50 +00:00
int W , H ;
2010-04-12 01:33:10 +00:00
W = OpenGL_GetBackbufferWidth ();
H = OpenGL_GetBackbufferHeight ();
2009-06-08 02:48:38 +00:00
2009-10-22 20:22:50 +00:00
std :: string OSDM1 =
2010-06-05 01:38:22 +00:00
g_ActiveConfig . bNativeResolution || g_ActiveConfig . b2xResolution ?
2009-10-22 20:22:50 +00:00
( g_ActiveConfig . bNativeResolution ?
StringFromFormat ( "%i x %i (native)" , OSDInternalW , OSDInternalH )
: StringFromFormat ( "%i x %i (2x)" , OSDInternalW , OSDInternalH ))
: StringFromFormat ( "%i x %i (custom)" , W , H );
2010-01-29 07:44:21 +00:00
std :: string OSDM21 ;
switch ( g_ActiveConfig . iAspectRatio )
{
case ASPECT_AUTO :
OSDM21 = "Auto" ;
break ;
case ASPECT_FORCE_16_9 :
OSDM21 = "16:9" ;
break ;
case ASPECT_FORCE_4_3 :
OSDM21 = "4:3" ;
break ;
case ASPECT_STRETCH :
OSDM21 = "Stretch" ;
break ;
}
2009-10-22 20:22:50 +00:00
std :: string OSDM22 =
2010-06-05 01:38:22 +00:00
g_ActiveConfig . bCrop ? " (crop)" : "" ;
2010-01-29 07:44:21 +00:00
std :: string OSDM3 = g_ActiveConfig . bEFBCopyDisable ? "Disabled" :
g_ActiveConfig . bCopyEFBToTexture ? "To Texture" : "To RAM" ;
2009-06-08 02:48:38 +00:00
2009-10-22 20:22:50 +00:00
// If there is more text than this we will have a collission
if ( g_ActiveConfig . bShowFPS )
{ T1 += " \n\n " ; T2 += " \n\n " ; }
2009-06-08 02:48:38 +00:00
2009-10-22 20:22:50 +00:00
// The rows
T0 . push_back ( StringFromFormat ( "3: Internal Resolution: %s \n " , OSDM1 . c_str ()));
2010-01-29 07:44:21 +00:00
T0 . push_back ( StringFromFormat ( "4: Aspect Ratio: %s%s \n " , OSDM21 . c_str (), OSDM22 . c_str ()));
T0 . push_back ( StringFromFormat ( "5: Copy EFB: %s \n " , OSDM3 . c_str ()));
2009-10-22 20:22:50 +00:00
T0 . push_back ( StringFromFormat ( "6: Fog: %s \n " , g_ActiveConfig . bDisableFog ? "Disabled" : "Enabled" ));
2010-06-05 01:38:22 +00:00
T0 . push_back ( StringFromFormat ( "7: Material Lighting: %s \n " , g_ActiveConfig . bDisableLighting ? "Disabled" : "Enabled" ));
2009-09-06 15:39:06 +00:00
2009-10-22 20:22:50 +00:00
// The latest changed setting in yellow
T1 += ( OSDChoice == - 1 ) ? T0 . at ( 0 ) : " \n " ;
T1 += ( OSDChoice == - 2 ) ? T0 . at ( 1 ) : " \n " ;
T1 += ( OSDChoice == - 3 ) ? T0 . at ( 2 ) : " \n " ;
T1 += ( OSDChoice == - 4 ) ? T0 . at ( 3 ) : " \n " ;
2010-06-05 01:38:22 +00:00
T1 += ( OSDChoice == - 5 ) ? T0 . at ( 4 ) : " \n " ;
2009-09-06 15:39:06 +00:00
2009-10-22 20:22:50 +00:00
// The other settings in cyan
T2 += ( OSDChoice != - 1 ) ? T0 . at ( 0 ) : " \n " ;
T2 += ( OSDChoice != - 2 ) ? T0 . at ( 1 ) : " \n " ;
T2 += ( OSDChoice != - 3 ) ? T0 . at ( 2 ) : " \n " ;
T2 += ( OSDChoice != - 4 ) ? T0 . at ( 3 ) : " \n " ;
2010-06-05 01:38:22 +00:00
T2 += ( OSDChoice != - 5 ) ? T0 . at ( 4 ) : " \n " ;
2009-06-08 02:48:38 +00:00
2009-10-22 20:22:50 +00:00
// Render a shadow, and then the text
Renderer :: RenderText ( T1 . c_str (), 21 , 21 , 0xDD000000 );
Renderer :: RenderText ( T1 . c_str (), 20 , 20 , 0xFFffff00 );
Renderer :: RenderText ( T2 . c_str (), 21 , 21 , 0xDD000000 );
Renderer :: RenderText ( T2 . c_str (), 20 , 20 , 0xFF00FFFF );
}
2009-06-08 02:48:38 +00:00
}
2009-02-28 16:33:59 +00:00
}
2009-02-23 07:23:34 +00:00
void Renderer :: RenderText ( const char * pstr , int left , int top , u32 color )
{
2009-02-28 16:33:59 +00:00
int nBackbufferWidth = ( int ) OpenGL_GetBackbufferWidth ();
int nBackbufferHeight = ( int ) OpenGL_GetBackbufferHeight ();
2010-06-05 01:38:22 +00:00
glColor4f ((( color >> 16 ) & 0xff ) / 255.0f , (( color >> 8 ) & 0xff ) / 255.0f ,
(( color >> 0 ) & 0xff ) / 255.0f , (( color >> 24 ) & 0xFF ) / 255.0f );
s_pfont -> printMultilineText ( pstr ,
left * 2.0f / ( float ) nBackbufferWidth - 1 ,
1 - top * 2.0f / ( float ) nBackbufferHeight ,
2009-02-23 07:23:34 +00:00
0 , nBackbufferWidth , nBackbufferHeight );
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ();
2009-02-23 07:23:34 +00:00
}
2009-06-07 11:51:53 +00:00
// Save screenshot
2009-02-27 03:56:34 +00:00
void Renderer :: SetScreenshot ( const char * filename )
2009-02-23 07:23:34 +00:00
{
2009-02-27 03:56:34 +00:00
s_criticalScreenshot . Enter ();
s_sScreenshotName = filename ;
s_bScreenshot = true ;
s_criticalScreenshot . Leave ();
}
2009-02-23 07:23:34 +00:00
2009-07-31 01:55:26 +00:00
#if defined(HAVE_WX) && HAVE_WX
2009-07-29 03:11:35 +00:00
THREAD_RETURN TakeScreenshot ( void * pArgs )
{
ScrStrct * threadStruct = ( ScrStrct * ) pArgs ;
// 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
{
2010-01-13 21:11:02 +00:00
bool use16_9 = g_VideoInitialize . bAutoAspectIs16_9 ;
// 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-06-05 01:38: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 ));
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-06-05 01:38: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
2010-05-29 10:09:24 +00:00
threadStruct -> img -> SaveFile ( wxString :: FromAscii ( threadStruct -> filename . c_str ()), wxBITMAP_TYPE_PNG );
2009-07-29 03:11:35 +00:00
threadStruct -> img -> Destroy ();
// Show success messages
OSD :: AddMessage ( StringFromFormat ( "Saved %i x %i %s" , ( int ) FloatW , ( int ) FloatH , threadStruct -> filename . c_str ()). c_str (), 2000 );
2009-07-31 01:55:26 +00:00
delete threadStruct ;
2009-07-29 03:11:35 +00:00
return 0 ;
}
2009-07-31 01:55:26 +00:00
#endif
2009-07-29 03:11:35 +00:00
2009-06-06 13:36:33 +00:00
bool Renderer :: SaveRenderTarget ( const char * filename , int W , int H , int YOffset )
2009-02-27 03:56:34 +00:00
{
2009-06-06 13:36:33 +00:00
u8 * data = ( u8 * ) malloc ( 3 * W * H );
2009-02-27 03:56:34 +00:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 );
2010-06-05 01:38:22 +00:00
2009-07-28 23:38:49 +00:00
glReadPixels ( 0 , Renderer :: GetTargetHeight () - H + YOffset , W , H , GL_RGB , GL_UNSIGNED_BYTE , data );
2010-06-05 01:38:22 +00:00
2009-06-06 17:34:54 +00:00
// Show failure message
2009-02-27 03:56:34 +00:00
if ( glGetError () != GL_NO_ERROR )
2009-06-06 17:34:54 +00:00
{
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-06-05 01:38:22 +00:00
2009-06-06 13:36:33 +00:00
// Turn image upside down
FlipImageData ( data , W , H );
2010-06-05 01:38: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-06-05 01:38:22 +00:00
2009-07-29 03:11:35 +00:00
if ( scrshotThread )
2009-07-28 23:38:49 +00:00
{
2009-07-29 03:11:35 +00:00
delete scrshotThread ;
scrshotThread = NULL ;
2009-07-28 23:38:49 +00:00
}
2010-06-05 01:38:22 +00:00
2009-07-29 03:11:35 +00:00
ScrStrct * threadStruct = new ScrStrct ;
threadStruct -> filename = std :: string ( filename );
threadStruct -> img = a ;
threadStruct -> H = H ; threadStruct -> W = W ;
2010-06-05 01:38:22 +00:00
2009-07-29 03:11:35 +00:00
scrshotThread = new Common :: Thread ( TakeScreenshot , threadStruct );
2009-07-31 01:55:26 +00:00
#ifdef _WIN32
scrshotThread -> SetPriority ( THREAD_PRIORITY_BELOW_NORMAL );
#endif
2009-03-28 21:07:16 +00:00
bool result = true ;
2010-06-05 01:38:22 +00:00
2009-07-29 03:11:35 +00:00
OSD :: AddMessage ( "Saving Screenshot... " , 2000 );
2010-06-05 01:38:22 +00:00
2009-03-28 21:07:16 +00:00
#else
2009-07-13 06:34:12 +00:00
bool result = SaveTGA ( filename , W , H , data );
2009-07-28 23:38:49 +00:00
free ( data );
2009-07-29 00:49:12 +00:00
#endif
2010-06-05 01:38:22 +00:00
2009-03-28 21:07:16 +00:00
return result ;
}
2009-06-07 11:51:53 +00:00
2009-03-28 21:07:16 +00:00
void Renderer :: FlipImageData ( u8 * data , int w , int h )
{
2009-02-28 16:33:59 +00:00
// 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 ]);
2009-02-27 03:56:34 +00:00
}
}
2009-02-23 07:23:34 +00:00
}
2009-06-07 11:51:53 +00:00
2009-09-13 08:21:35 +00:00
// Called from VertexShaderManager
2009-02-23 07:23:34 +00:00
void UpdateViewport ()
{
2009-11-23 14:08:08 +00:00
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
2010-06-05 01:38:22 +00:00
// [0] = width/2
// [1] = height/2
// [2] = 16777215 * (farz - nearz)
// [3] = xorig + width/2 + 342
// [4] = yorig + height/2 + 342
// [5] = 16777215 * farz
2009-09-03 19:24:16 +00:00
int scissorXOff = bpmem . scissorOffset . x * 2 ; // 342
int scissorYOff = bpmem . scissorOffset . y * 2 ; // 342
2010-05-19 03:15:36 +00:00
2009-02-23 07:23:34 +00:00
// Stretch picture with increased internal resolution
2010-05-19 03:15:36 +00:00
int GLx = ( int ) ceil (( xfregs . rawViewport [ 3 ] - xfregs . rawViewport [ 0 ] - scissorXOff ) * EFBxScale );
int GLy = ( int ) ceil (( float )(( int )( EFB_HEIGHT - xfregs . rawViewport [ 4 ] + xfregs . rawViewport [ 1 ] + scissorYOff )) * EFByScale );
int GLWidth = ( int ) ceil (( float )( 2 * xfregs . rawViewport [ 0 ]) * EFBxScale );
int GLHeight = ( int ) ceil (( float )( - 2 * xfregs . rawViewport [ 1 ]) * EFByScale );
2009-10-26 02:38:23 +00:00
double GLNear = ( xfregs . rawViewport [ 5 ] - xfregs . rawViewport [ 2 ]) / 16777216.0f ;
2009-11-23 14:08:08 +00:00
double GLFar = xfregs . rawViewport [ 5 ] / 16777216.0f ;
if ( GLWidth < 0 )
{
GLx += GLWidth ;
2010-06-05 01:38:22 +00:00
GLWidth *=- 1 ;
2009-11-23 14:08:08 +00:00
}
if ( GLHeight < 0 )
{
GLy += GLHeight ;
GLHeight *= - 1 ;
}
2009-02-23 07:23:34 +00:00
// Update the view port
2009-02-28 16:33:59 +00:00
glViewport ( GLx , GLy , GLWidth , GLHeight );
2009-02-23 07:23:34 +00:00
glDepthRange ( GLNear , GLFar );
}
2009-11-27 19:42:27 +00:00
void Renderer :: SetGenerationMode ()
{
// none, ccw, cw, ccw
2010-06-05 01:38:22 +00:00
if ( bpmem . genMode . cullmode > 0 )
2009-11-27 19:42:27 +00:00
{
2010-06-05 01:38:22 +00:00
glEnable ( GL_CULL_FACE );
glFrontFace ( bpmem . genMode . cullmode == 2 ? GL_CCW : GL_CW );
}
else
2009-11-27 19:42:27 +00:00
glDisable ( GL_CULL_FACE );
}
void Renderer :: SetDepthMode ()
{
2010-06-05 01:38:22 +00:00
if ( bpmem . zmode . testenable )
2009-11-27 19:42:27 +00:00
{
glEnable ( GL_DEPTH_TEST );
glDepthMask ( bpmem . zmode . updateenable ? GL_TRUE : GL_FALSE );
glDepthFunc ( glCmpFuncs [ bpmem . zmode . func ]);
}
2010-06-05 01:38:22 +00:00
else
2009-11-27 19:42:27 +00:00
{
// if the test is disabled write is disabled too
glDisable ( GL_DEPTH_TEST );
glDepthMask ( GL_FALSE );
2010-06-05 01:38:22 +00:00
}
2009-11-27 19:42:27 +00:00
}
void Renderer :: SetLogicOpMode ()
{
2010-06-05 01:38:22 +00:00
if ( bpmem . blendmode . logicopenable && bpmem . blendmode . logicmode != 3 )
2009-11-27 19:42:27 +00:00
{
glEnable ( GL_COLOR_LOGIC_OP );
glLogicOp ( glLogicOpCodes [ bpmem . blendmode . logicmode ]);
}
2010-06-05 01:38:22 +00:00
else
2009-11-27 19:42:27 +00:00
glDisable ( GL_COLOR_LOGIC_OP );
}
void Renderer :: SetDitherMode ()
{
2010-06-05 01:38:22 +00:00
if ( bpmem . blendmode . dither )
2009-11-27 19:42:27 +00:00
glEnable ( GL_DITHER );
2010-06-05 01:38:22 +00:00
else
2009-11-27 19:42:27 +00:00
glDisable ( GL_DITHER );
}
void Renderer :: SetLineWidth ()
{
float fratio = xfregs . rawViewport [ 0 ] != 0 ? (( float ) Renderer :: GetTargetWidth () / EFB_WIDTH ) : 1.0f ;
if ( bpmem . lineptwidth . linesize > 0 )
glLineWidth (( float ) bpmem . lineptwidth . linesize * fratio / 6.0f ); // scale by ratio of widths
if ( bpmem . lineptwidth . pointsize > 0 )
glPointSize (( float ) bpmem . lineptwidth . pointsize * fratio / 6.0f );
}
void Renderer :: SetSamplerState ( int stage , int texindex )
{
// TODO
}
void Renderer :: SetInterlacingMode ()
{
// TODO
}