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-06-07 12:06:15 +00:00
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-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 )
2009-06-28 23:35:08 +00:00
{
2010-05-19 03:15:36 +00:00
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-06-28 23:35:08 +00:00
}
2010-05-19 03:15:36 +00:00
EFBxScale = ceilf ( xScale ) ;
EFByScale = ceilf ( yScale ) ;
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 ( ) ;
// load the effect, find the best profiles (if any)
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBVP1 ) ! = CG_TRUE ) {
ERROR_LOG ( VIDEO , " arbvp1 not supported " ) ;
return false ;
}
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBFP1 ) ! = CG_TRUE ) {
ERROR_LOG ( VIDEO , " arbfp1 not supported " ) ;
return false ;
}
g_cgvProf = cgGLGetLatestProfile ( CG_GL_VERTEX ) ;
g_cgfProf = cgGLGetLatestProfile ( CG_GL_FRAGMENT ) ;
cgGLSetOptimalOptions ( g_cgvProf ) ;
cgGLSetOptimalOptions ( g_cgfProf ) ;
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 ) ;
glViewport ( 0 , 0 , GetTargetWidth ( ) , GetTargetHeight ( ) ) ; // Reset The Current Viewport
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
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 ) ;
glScissor ( 0 , 0 , GetTargetWidth ( ) , GetTargetHeight ( ) ) ;
glBlendColorEXT ( 0 , 0 , 0 , 0.5f ) ;
glClearDepth ( 1.0f ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
// 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-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-23 07:23:34 +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 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-15 21:19:09 +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 )
{
2010-06-19 21:12:09 +00:00
2009-07-15 00:51:24 +00:00
// Update the view port for clearing the picture
TargetRectangle targetRc = Renderer : : ConvertEFBRectangle ( rc ) ;
2010-06-19 21:12:09 +00:00
glViewport ( targetRc . left , targetRc . bottom , targetRc . GetWidth ( ) , targetRc . GetHeight ( ) ) ;
glScissor ( targetRc . left , targetRc . bottom , targetRc . GetWidth ( ) , targetRc . GetHeight ( ) ) ;
2009-07-15 00:51:24 +00:00
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
2010-06-19 21:12:09 +00:00
2009-07-15 00:51:24 +00:00
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 ,
2010-06-19 21:12:09 +00:00
( ( color > > 24 ) & 0xFF ) / 255.0f
2009-07-15 00:51:24 +00:00
) ;
}
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-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
{
fixed fps limiting when using using virtual xfb, now fps = vps, in fact now real xfb is as fast as no using xfb, i'm thinking now that the correct thing is leave it enabled as default, and even remove the option.
the problem is one strange behavior i found, in opengl when xfb is enable, frame limit causes the frame rate to be limited exact half the correct speed, so if you choose auto and the game uses 30 fps you get 15 fps
so in opengl, you have to limit to the exact double of the game speed, 100 to pal games and 120 to ntsc.
in d3d this not happened every time, it just happen when you change some time consuming setting like changing the ssaa or resizing the window, in that case you have to disable and re enable frame limit to get the correct fps
to all the devs please if you can help me debug this, will give you a lot of thanks as i'm short in time to debug this error and is driving me crazy not to find the source of the problem.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5249 8ced0084-cf51-0410-be5f-012b33b47a6e
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-28 16:33:59 +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-23 07:23:34 +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
2009-02-28 19:02:37 +00:00
2009-06-26 08:57:53 +00:00
// Disable all other stages
for ( int i = 1 ; i < 8 ; + + i )
TextureMngr : : DisableStage ( i ) ;
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
// Update GLViewPort
2009-07-15 00:51:24 +00:00
glViewport ( back_rc . left , back_rc . bottom , back_rc . GetWidth ( ) , back_rc . GetHeight ( ) ) ;
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
GL_REPORT_ERRORD ( ) ;
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
// Copy the framebuffer to screen.
// Render to the real buffer now.
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ) ; // switch to the window backbuffer
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
// 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-06-26 08:57:53 +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-06-26 08:57:53 +00:00
}
glBindTexture ( GL_TEXTURE_RECTANGLE_ARB , 0 ) ;
TextureMngr : : DisableStage ( 0 ) ;
2009-02-23 07:23:34 +00:00
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 ( ) ;
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-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-06-24 15:58:06 +00:00
g_VideoInitialize . pCopiedToXFB ( XFBWrited | | g_ActiveConfig . bUseRealXFB ) ;
2010-03-25 22:01:33 +00:00
XFBWrited = false ;
2010-06-24 15:58:06 +00:00
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 ;
int W , H ;
2010-04-12 01:33:10 +00:00
W = OpenGL_GetBackbufferWidth ( ) ;
H = OpenGL_GetBackbufferHeight ( ) ;
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-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 " ; }
// 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-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-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-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-06-07 21:10:02 +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-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
}