2009-07-28 21:32:10 +00:00
// Copyright (C) 2003 Dolphin Project.
2008-12-08 05:25:12 +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-02-28 22:10:38 +00:00
#include <list>
2008-12-08 05:25:12 +00:00
#include <d3dx9.h>
2010-01-29 07:44:21 +00:00
#include "StringUtil.h"
2008-12-08 05:25:12 +00:00
#include "Common.h"
2010-03-14 18:57:50 +00:00
#include "Atomic.h"
2010-02-02 21:56:29 +00:00
#include "FileUtil.h"
2010-01-27 22:07:59 +00:00
#include "Thread.h"
2010-01-21 21:27:52 +00:00
#include "Timer.h"
2008-12-08 05:25:12 +00:00
#include "Statistics.h"
2011-03-15 23:09:12 +00:00
#include "Host.h"
2008-12-08 05:25:12 +00:00
2009-09-13 09:23:30 +00:00
#include "VideoConfig.h"
2008-12-08 05:25:12 +00:00
#include "main.h"
#include "VertexManager.h"
2010-10-24 19:52:52 +00:00
#include "PixelEngine.h"
2008-12-08 05:25:12 +00:00
#include "Render.h"
#include "OpcodeDecoding.h"
2009-06-22 09:31:30 +00:00
#include "BPStructs.h"
2008-12-08 05:25:12 +00:00
#include "XFStructs.h"
#include "D3DUtil.h"
2008-12-25 15:56:36 +00:00
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
2009-02-28 22:10:38 +00:00
#include "VertexShaderCache.h"
2008-12-26 19:39:12 +00:00
#include "PixelShaderCache.h"
2009-09-13 17:46:33 +00:00
#include "VertexLoaderManager.h"
2008-12-08 05:25:12 +00:00
#include "TextureCache.h"
#include "EmuWindow.h"
2009-03-28 21:07:16 +00:00
#include "AVIDump.h"
2009-09-03 20:37:35 +00:00
#include "OnScreenDisplay.h"
2009-09-13 17:46:33 +00:00
#include "FramebufferManager.h"
2009-09-04 06:09:21 +00:00
#include "Fifo.h"
2009-11-20 18:46:30 +00:00
#include "TextureConverter.h"
2010-08-29 23:08:56 +00:00
#include "DLCache.h"
2010-12-05 14:15:36 +00:00
#include "Debugger.h"
2011-01-31 01:28:32 +00:00
#include "Core.h"
2011-06-24 06:50:50 +00:00
#include "Movie.h"
2011-09-05 22:04:28 +02:00
#include "BPFunctions.h"
2012-10-04 05:41:02 +02:00
#include "FPSCounter.h"
2012-11-11 17:57:06 -05:00
#include "ConfigManager.h"
2009-09-02 06:33:41 +00:00
2012-12-23 20:25:11 +13:00
#include <strsafe.h>
2011-01-29 20:16:51 +00:00
namespace DX9
{
2010-09-28 02:15:02 +00:00
static int s_fps = 0 ;
2010-02-20 04:18:19 +00:00
2009-10-10 23:36:18 +00:00
static u32 s_blendMode ;
2010-02-03 22:19:00 +00:00
static u32 s_LastAA ;
2010-02-04 22:25:09 +00:00
static bool IS_AMD ;
2010-06-20 22:23:34 +00:00
static char * st ;
2008-12-08 05:25:12 +00:00
2010-01-27 22:07:59 +00:00
static LPDIRECT3DSURFACE9 ScreenShootMEMSurface = NULL ;
2009-11-08 20:35:11 +00:00
2009-09-13 17:46:33 +00:00
void SetupDeviceObjects ()
{
D3D :: font . Init ();
VertexLoaderManager :: Init ();
2010-11-14 23:31:53 +00:00
g_framebuffer_manager = new FramebufferManager ;
2009-09-15 21:05:31 +00:00
2009-09-15 21:49:15 +00:00
VertexShaderManager :: Dirty ();
PixelShaderManager :: Dirty ();
2009-11-20 18:46:30 +00:00
TextureConverter :: Init ();
2010-06-19 16:22:24 +00:00
// To avoid shader compilation stutters, read back all shaders from cache.
VertexShaderCache :: Init ();
PixelShaderCache :: Init ();
2012-10-20 10:22:15 -03:00
g_vertex_manager -> CreateDeviceObjects ();
2010-06-19 16:22:24 +00:00
// Texture cache will recreate themselves over time.
2009-09-13 17:46:33 +00:00
}
// Kill off all POOL_DEFAULT device objects.
void TeardownDeviceObjects ()
{
2010-01-28 04:30:07 +00:00
if ( ScreenShootMEMSurface )
ScreenShootMEMSurface -> Release ();
ScreenShootMEMSurface = NULL ;
2009-09-15 19:53:22 +00:00
D3D :: dev -> SetRenderTarget ( 0 , D3D :: GetBackBufferSurface ());
D3D :: dev -> SetDepthStencilSurface ( D3D :: GetBackBufferDepthSurface ());
2010-11-14 23:31:53 +00:00
delete g_framebuffer_manager ;
2009-09-13 17:46:33 +00:00
D3D :: font . Shutdown ();
2012-05-28 11:37:14 +02:00
TextureCache :: Invalidate ();
2009-09-13 17:46:33 +00:00
VertexLoaderManager :: Shutdown ();
2010-06-19 16:22:24 +00:00
VertexShaderCache :: Shutdown ();
PixelShaderCache :: Shutdown ();
2009-11-20 18:46:30 +00:00
TextureConverter :: Shutdown ();
2012-10-20 10:22:15 -03:00
g_vertex_manager -> DestroyDeviceObjects ();
2009-09-13 17:46:33 +00:00
}
2010-09-28 02:15:02 +00:00
// Init functions
2010-11-18 02:21:26 +00:00
Renderer :: Renderer ()
2008-12-08 05:25:12 +00:00
{
2012-10-04 05:41:02 +02:00
InitFPSCounter ();
2010-06-20 22:23:34 +00:00
st = new char [ 32768 ];
2010-11-18 02:21:26 +00:00
2010-04-22 04:28:34 +00:00
int fullScreenRes , x , y , w_temp , h_temp ;
2010-01-28 13:38:09 +00:00
s_blendMode = 0 ;
2010-06-05 00:01:18 +00:00
// Multisample Anti-aliasing hasn't been implemented yet use supersamling instead
int backbuffer_ms_mode = 0 ;
2009-09-15 08:13:45 +00:00
2011-03-15 23:09:12 +00:00
Host_GetRenderWindowSize ( x , y , w_temp , h_temp );
2009-09-15 08:13:45 +00:00
2009-11-08 02:28:06 +00:00
for ( fullScreenRes = 0 ; fullScreenRes < ( int ) D3D :: GetAdapter ( g_ActiveConfig . iAdapter ). resolutions . size (); fullScreenRes ++ )
2009-09-15 08:13:45 +00:00
{
2009-09-17 05:07:16 +00:00
if (( D3D :: GetAdapter ( g_ActiveConfig . iAdapter ). resolutions [ fullScreenRes ]. xres == w_temp ) &&
( D3D :: GetAdapter ( g_ActiveConfig . iAdapter ). resolutions [ fullScreenRes ]. yres == h_temp ))
2009-09-15 08:13:45 +00:00
break ;
}
2009-09-17 05:57:38 +00:00
if ( fullScreenRes == D3D :: GetAdapter ( g_ActiveConfig . iAdapter ). resolutions . size ())
fullScreenRes = 0 ;
2010-07-06 13:14:51 +00:00
D3D :: Create ( g_ActiveConfig . iAdapter , EmuWindow :: GetWnd (),
2009-09-15 19:53:22 +00:00
fullScreenRes , backbuffer_ms_mode , false );
2009-03-01 01:09:32 +00:00
2010-02-04 22:25:09 +00:00
IS_AMD = D3D :: IsATIDevice ();
2010-09-28 02:15:02 +00:00
// Decide frambuffer size
2009-09-13 17:46:33 +00:00
s_backbuffer_width = D3D :: GetBackBufferWidth ();
s_backbuffer_height = D3D :: GetBackBufferHeight ();
2009-03-01 12:07:34 +00:00
2012-09-28 23:48:18 +02:00
FramebufferManagerBase :: SetLastXfbWidth ( MAX_XFB_WIDTH );
FramebufferManagerBase :: SetLastXfbHeight ( MAX_XFB_HEIGHT );
2010-03-14 18:57:50 +00:00
2012-09-29 00:04:55 +02:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height );
2011-01-02 23:13:29 +00:00
2010-06-09 15:33:01 +00:00
s_LastAA = g_ActiveConfig . iMultisampleMode ;
2013-01-16 15:46:11 -05:00
int SupersampleCoeficient = ( s_LastAA % 3 ) + 1 ;
2010-05-19 03:15:36 +00:00
2010-11-18 02:21:26 +00:00
s_LastEFBScale = g_ActiveConfig . iEFBScale ;
2013-01-16 15:46:11 -05:00
CalculateTargetSize ( s_backbuffer_width , s_backbuffer_height , SupersampleCoeficient );
2011-01-02 23:13:29 +00:00
// Make sure to use valid texture sizes
2011-05-12 02:14:45 +00:00
D3D :: FixTextureSize ( s_target_width , s_target_height );
2011-01-02 23:13:29 +00:00
2010-04-03 22:22:55 +00:00
// We're not using fixed function.
2009-09-03 19:24:16 +00:00
// Let's just set the matrices to identity to be sure.
2009-02-28 22:10:38 +00:00
D3DXMATRIX mtx ;
D3DXMatrixIdentity ( & mtx );
D3D :: dev -> SetTransform ( D3DTS_VIEW , & mtx );
D3D :: dev -> SetTransform ( D3DTS_WORLD , & mtx );
2009-09-13 17:46:33 +00:00
SetupDeviceObjects ();
2009-09-03 20:37:35 +00:00
2013-01-16 15:46:11 -05:00
for ( int stage = 0 ; stage < 8 ; stage ++ )
2011-01-31 13:17:57 +00:00
D3D :: SetSamplerState ( stage , D3DSAMP_MAXANISOTROPY , 1 << g_ActiveConfig . iMaxAnisotropy );
2010-01-17 17:44:09 +00:00
2009-11-08 20:35:11 +00:00
D3DVIEWPORT9 vp ;
vp . X = 0 ;
vp . Y = 0 ;
vp . Width = s_backbuffer_width ;
vp . Height = s_backbuffer_height ;
vp . MinZ = 0.0f ;
2009-11-20 18:46:30 +00:00
vp . MaxZ = 1.0f ;
2009-11-08 20:35:11 +00:00
D3D :: dev -> SetViewport ( & vp );
2009-09-13 17:46:33 +00:00
D3D :: dev -> Clear ( 0 , NULL , D3DCLEAR_TARGET , 0x0 , 0 , 0 );
2009-11-08 20:35:11 +00:00
2010-11-14 23:31:53 +00:00
D3D :: dev -> SetRenderTarget ( 0 , FramebufferManager :: GetEFBColorRTSurface ());
D3D :: dev -> SetDepthStencilSurface ( FramebufferManager :: GetEFBDepthRTSurface ());
2011-05-12 02:14:45 +00:00
vp . X = 0 ;
vp . Y = 0 ;
2009-11-08 20:35:11 +00:00
vp . Width = s_target_width ;
vp . Height = s_target_height ;
D3D :: dev -> SetViewport ( & vp );
2011-01-06 16:05:11 +00:00
D3D :: dev -> Clear ( 0 , NULL , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB ( 0 , 0 , 0 ), 1.0f , 0 );
2009-09-13 17:46:33 +00:00
D3D :: BeginFrame ();
2009-10-30 04:14:43 +00:00
D3D :: SetRenderState ( D3DRS_SCISSORTESTENABLE , true );
2010-07-09 20:56:16 +00:00
D3D :: dev -> CreateOffscreenPlainSurface ( s_backbuffer_width , s_backbuffer_height , D3DFMT_X8R8G8B8 , D3DPOOL_SYSTEMMEM , & ScreenShootMEMSurface , NULL );
2008-12-08 05:25:12 +00:00
}
2010-11-18 02:21:26 +00:00
Renderer ::~ Renderer ()
2008-12-08 05:25:12 +00:00
{
2009-09-13 17:46:33 +00:00
TeardownDeviceObjects ();
2008-12-08 05:25:12 +00:00
D3D :: EndFrame ();
2009-09-20 03:29:43 +00:00
D3D :: Present ();
2008-12-08 05:25:12 +00:00
D3D :: Close ();
2010-02-25 06:12:35 +00:00
2010-11-18 02:21:26 +00:00
delete [] st ;
2010-01-29 07:44:21 +00:00
}
2009-09-03 19:42:45 +00:00
void Renderer :: RenderText ( const char * text , int left , int top , u32 color )
2008-12-08 05:25:12 +00:00
{
2010-11-07 10:11:58 +00:00
D3D :: font . DrawTextScaled (( float ) left , ( float ) top , 20 , 20 , 0.0f , color , text );
2008-12-08 05:25:12 +00:00
}
2009-09-03 21:56:08 +00:00
TargetRectangle Renderer :: ConvertEFBRectangle ( const EFBRectangle & rc )
{
2010-09-30 15:24:34 +00:00
TargetRectangle result ;
2011-05-12 02:14:45 +00:00
result . left = EFBToScaledX ( rc . left );
result . top = EFBToScaledY ( rc . top );
result . right = EFBToScaledX ( rc . right );
result . bottom = EFBToScaledY ( rc . bottom );
2009-09-03 21:56:08 +00:00
return result ;
}
2010-11-18 02:21:26 +00:00
}
2013-02-26 20:47:48 -05:00
void formatBufferDump ( const u8 * in , u8 * out , int w , int h , int p )
2009-03-28 21:07:16 +00:00
{
2009-09-03 21:56:08 +00:00
for ( int y = 0 ; y < h ; y ++ )
{
2013-02-26 20:47:48 -05:00
auto line = in + ( h - y - 1 ) * p ;
2009-09-03 21:56:08 +00:00
for ( int x = 0 ; x < w ; x ++ )
{
2009-03-28 21:07:16 +00:00
memcpy ( out , line , 3 );
out += 3 ;
line += 4 ;
2010-07-09 20:56:16 +00:00
}
2009-03-28 21:07:16 +00:00
}
}
2010-11-18 02:21:26 +00:00
namespace DX9
{
2009-09-15 19:53:22 +00:00
// With D3D, we have to resize the backbuffer if the window changed
// size.
2010-11-18 02:21:26 +00:00
bool Renderer :: CheckForResize ()
2009-09-15 19:53:22 +00:00
{
while ( EmuWindow :: IsSizing ())
Sleep ( 10 );
2010-09-28 02:15:02 +00:00
2010-01-28 04:30:07 +00:00
if ( EmuWindow :: GetParentWnd ())
{
// Re-stretch window to parent window size again, if it has a parent window.
RECT rcParentWindow ;
GetWindowRect ( EmuWindow :: GetParentWnd (), & rcParentWindow );
int width = rcParentWindow . right - rcParentWindow . left ;
int height = rcParentWindow . bottom - rcParentWindow . top ;
2010-11-18 02:21:26 +00:00
if ( width != Renderer :: GetBackbufferWidth () || height != Renderer :: GetBackbufferHeight ())
2010-07-06 13:14:51 +00:00
MoveWindow ( EmuWindow :: GetWnd (), 0 , 0 , width , height , FALSE );
2010-01-28 04:30:07 +00:00
}
2010-11-18 02:21:26 +00:00
2009-09-15 19:53:22 +00:00
RECT rcWindow ;
GetClientRect ( EmuWindow :: GetWnd (), & rcWindow );
int client_width = rcWindow . right - rcWindow . left ;
int client_height = rcWindow . bottom - rcWindow . top ;
2010-09-28 02:15:02 +00:00
// Sanity check
2010-11-18 02:21:26 +00:00
if (( client_width != Renderer :: GetBackbufferWidth () ||
client_height != Renderer :: GetBackbufferHeight ()) &&
2009-09-15 19:53:22 +00:00
client_width >= 4 && client_height >= 4 )
{
TeardownDeviceObjects ();
2010-07-06 13:14:51 +00:00
D3D :: Reset ();
2009-09-15 19:53:22 +00:00
s_backbuffer_width = D3D :: GetBackBufferWidth ();
s_backbuffer_height = D3D :: GetBackBufferHeight ();
2010-07-09 20:56:16 +00:00
if ( ScreenShootMEMSurface )
ScreenShootMEMSurface -> Release ();
2010-11-18 02:21:26 +00:00
D3D :: dev -> CreateOffscreenPlainSurface ( Renderer :: GetBackbufferWidth (), Renderer :: GetBackbufferHeight (),
D3DFMT_X8R8G8B8 , D3DPOOL_SYSTEMMEM , & ScreenShootMEMSurface , NULL );
2009-09-15 19:53:22 +00:00
2010-11-18 02:21:26 +00:00
return true ;
2009-09-20 05:04:45 +00:00
}
2010-11-18 02:21:26 +00:00
return false ;
2008-12-08 05:25:12 +00:00
}
2011-09-05 22:04:28 +02:00
void Renderer :: SetScissorRect ( const TargetRectangle & rc )
2008-12-08 05:25:12 +00:00
{
2011-09-05 22:04:28 +02:00
D3D :: dev -> SetScissorRect ( rc . AsRECT ());
2009-09-03 19:42:45 +00:00
}
2010-09-28 02:15:02 +00:00
void Renderer :: SetColorMask ()
2009-09-03 19:42:45 +00:00
{
2010-12-20 16:57:29 +00:00
// Only enable alpha channel if it's supported by the current EFB format
2009-09-13 08:21:35 +00:00
DWORD color_mask = 0 ;
2013-01-08 17:23:01 +01:00
if ( bpmem . alpha_test . TestResult () != AlphaTest :: FAIL )
{
if ( bpmem . blendmode . alphaupdate && ( bpmem . zcontrol . pixel_format == PIXELFMT_RGBA6_Z24 ))
color_mask = D3DCOLORWRITEENABLE_ALPHA ;
if ( bpmem . blendmode . colorupdate )
color_mask |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE ;
}
2009-09-13 08:21:35 +00:00
D3D :: SetRenderState ( D3DRS_COLORWRITEENABLE , color_mask );
2008-12-08 05:25:12 +00:00
}
2010-10-24 19:52:52 +00:00
// This function allows the CPU to directly access the EFB.
// There are EFB peeks (which will read the color or depth of a pixel)
// and EFB pokes (which will change the color or depth of a pixel).
//
// The behavior of EFB peeks can only be modified by:
// - GX_PokeAlphaRead
// The behavior of EFB pokes can be modified by:
// - GX_PokeAlphaMode (TODO)
// - GX_PokeAlphaUpdate (TODO)
// - GX_PokeBlendMode (TODO)
// - GX_PokeColorUpdate (TODO)
// - GX_PokeDither (TODO)
// - GX_PokeDstAlpha (TODO)
// - GX_PokeZMode (TODO)
2010-10-22 19:40:05 +00:00
u32 Renderer :: AccessEFB ( EFBAccessType type , u32 x , u32 y , u32 poke_data )
2009-09-04 17:29:16 +00:00
{
2010-01-17 17:44:09 +00:00
if ( ! g_ActiveConfig . bEFBAccessEnable )
2009-12-28 19:13:06 +00:00
return 0 ;
2010-10-22 19:40:05 +00:00
if ( type == POKE_Z )
2010-07-16 21:51:35 +00:00
{
static bool alert_only_once = true ;
if ( ! alert_only_once ) return 0 ;
2010-10-22 19:40:05 +00:00
PanicAlert ( "EFB: Poke Z not implemented (tried to poke z value %#x at (%d,%d))" , poke_data , x , y );
2010-07-16 21:51:35 +00:00
alert_only_once = false ;
return 0 ;
}
2011-01-04 12:56:52 +00:00
// if depth textures aren't supported by the hardware, just return
if ( type == PEEK_Z )
if ( FramebufferManager :: GetEFBDepthTexture () == NULL )
return 0 ;
2010-10-22 19:40:05 +00:00
// We're using three surfaces here:
// - pEFBSurf: EFB Surface. Source surface when peeking, destination surface when poking.
// - pBufferRT: A render target surface. When peeking, we render a textured quad to this surface.
// - pSystemBuf: An offscreen surface. Used to retrieve the pixel data from pBufferRT.
LPDIRECT3DSURFACE9 pEFBSurf , pBufferRT , pSystemBuf ;
if ( type == PEEK_Z || type == POKE_Z )
{
2010-11-14 23:31:53 +00:00
pEFBSurf = FramebufferManager :: GetEFBDepthRTSurface ();
pBufferRT = FramebufferManager :: GetEFBDepthReadSurface ();
pSystemBuf = FramebufferManager :: GetEFBDepthOffScreenRTSurface ();
2010-10-22 19:40:05 +00:00
}
else //if(type == PEEK_COLOR || type == POKE_COLOR)
{
2010-11-14 23:31:53 +00:00
pEFBSurf = FramebufferManager :: GetEFBColorRTSurface ();
pBufferRT = FramebufferManager :: GetEFBColorReadSurface ();
pSystemBuf = FramebufferManager :: GetEFBColorOffScreenRTSurface ();
2010-10-22 19:40:05 +00:00
}
2009-12-28 19:13:06 +00:00
2010-07-06 13:14:51 +00:00
// Buffer not found alert
2010-10-22 19:40:05 +00:00
if ( ! pEFBSurf ) {
2009-10-06 14:24:10 +00:00
PanicAlert ( "No %s!" , ( type == PEEK_Z || type == POKE_Z ) ? "Z-Buffer" : "Color EFB" );
return 0 ;
}
2010-10-22 19:40:05 +00:00
// Convert EFB dimensions to the ones of our render target
2009-09-04 17:29:16 +00:00
EFBRectangle efbPixelRc ;
efbPixelRc . left = x ;
efbPixelRc . top = y ;
efbPixelRc . right = x + 1 ;
efbPixelRc . bottom = y + 1 ;
2010-09-30 15:24:34 +00:00
TargetRectangle targetPixelRc = ConvertEFBRectangle ( efbPixelRc );
2009-09-04 17:29:16 +00:00
2009-10-03 02:12:24 +00:00
HRESULT hr ;
RECT RectToLock ;
RectToLock . bottom = targetPixelRc . bottom ;
RectToLock . left = targetPixelRc . left ;
RectToLock . right = targetPixelRc . right ;
2009-11-22 02:37:00 +00:00
RectToLock . top = targetPixelRc . top ;
2010-01-17 17:44:09 +00:00
if ( type == PEEK_Z )
2009-11-22 02:37:00 +00:00
{
2011-01-06 02:24:03 +00:00
// TODO: why is D3DFMT_D24X8 singled out here? why not D3DFMT_D24X4S4/D24S8/D24FS8/D32/D16/D15S1 too, or none of them?
2010-11-14 23:31:53 +00:00
if ( FramebufferManager :: GetEFBDepthRTSurfaceFormat () == D3DFMT_D24X8 )
2010-10-22 19:40:05 +00:00
return 0 ;
2009-11-22 02:37:00 +00:00
RECT PixelRect ;
PixelRect . bottom = 4 ;
PixelRect . left = 0 ;
PixelRect . right = 4 ;
PixelRect . top = 0 ;
RectToLock . bottom += 2 ;
RectToLock . right += 1 ;
RectToLock . top -= 1 ;
RectToLock . left -= 2 ;
2010-01-17 17:44:09 +00:00
if (( RectToLock . bottom - RectToLock . top ) > 4 )
2009-11-22 02:37:00 +00:00
RectToLock . bottom -- ;
2010-01-17 17:44:09 +00:00
if (( RectToLock . right - RectToLock . left ) > 4 )
2009-11-22 02:37:00 +00:00
RectToLock . left ++ ;
2010-09-28 02:15:02 +00:00
2010-07-06 13:14:51 +00:00
ResetAPIState (); // Reset any game specific settings
2010-10-22 19:40:05 +00:00
D3D :: dev -> SetDepthStencilSurface ( NULL );
D3D :: dev -> SetRenderTarget ( 0 , pBufferRT );
2009-11-22 02:37:00 +00:00
// Stretch picture with increased internal resolution
2010-10-22 19:40:05 +00:00
D3DVIEWPORT9 vp ;
2009-11-22 02:37:00 +00:00
vp . X = 0 ;
vp . Y = 0 ;
vp . Width = 4 ;
vp . Height = 4 ;
vp . MinZ = 0.0f ;
vp . MaxZ = 1.0f ;
2010-10-22 19:40:05 +00:00
D3D :: dev -> SetViewport ( & vp );
2011-01-07 19:23:57 +00:00
float colmat [ 28 ] = { 0.0f };
2009-11-22 02:37:00 +00:00
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = 1.0f ;
2011-01-07 19:23:57 +00:00
PixelShaderManager :: SetColorMatrix ( colmat ); // set transformation
2010-11-14 23:31:53 +00:00
LPDIRECT3DTEXTURE9 read_texture = FramebufferManager :: GetEFBDepthTexture ();
2009-11-22 02:37:00 +00:00
2010-07-06 13:14:51 +00:00
D3D :: ChangeSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_POINT );
2009-11-22 02:37:00 +00:00
2010-12-19 20:59:23 +00:00
D3DFORMAT bformat = FramebufferManager :: GetEFBDepthRTSurfaceFormat ();
2010-02-08 23:23:04 +00:00
D3D :: drawShadedTexQuad (
2010-10-22 19:40:05 +00:00
read_texture ,
& RectToLock ,
2011-05-12 02:14:45 +00:00
Renderer :: GetTargetWidth (),
Renderer :: GetTargetHeight (),
2010-10-22 19:40:05 +00:00
4 , 4 ,
2011-01-06 02:24:03 +00:00
PixelShaderCache :: GetDepthMatrixProgram ( 0 , bformat != FOURCC_RAWZ ),
2010-06-05 00:01:18 +00:00
VertexShaderCache :: GetSimpleVertexShader ( 0 ));
2009-11-22 02:37:00 +00:00
D3D :: RefreshSamplerState ( 0 , D3DSAMP_MINFILTER );
2010-11-14 23:31:53 +00:00
D3D :: dev -> SetRenderTarget ( 0 , FramebufferManager :: GetEFBColorRTSurface ());
D3D :: dev -> SetDepthStencilSurface ( FramebufferManager :: GetEFBDepthRTSurface ());
2009-11-22 02:37:00 +00:00
RestoreAPIState ();
2010-10-22 19:40:05 +00:00
// Retrieve the pixel data to the local memory buffer
2009-11-22 02:37:00 +00:00
RectToLock . bottom = 4 ;
RectToLock . left = 0 ;
RectToLock . right = 4 ;
RectToLock . top = 0 ;
2010-10-22 19:40:05 +00:00
D3D :: dev -> GetRenderTargetData ( pBufferRT , pSystemBuf );
// EFB data successfully retrieved, now get the pixel data
D3DLOCKED_RECT drect ;
pSystemBuf -> LockRect ( & drect , & RectToLock , D3DLOCK_READONLY );
2011-01-10 21:28:02 +00:00
u32 z = (( u32 * ) drect . pBits )[ 6 ]; // 24 bit depth value
2010-10-22 19:40:05 +00:00
pSystemBuf -> UnlockRect ();
2011-01-10 21:28:02 +00:00
// if Z is in 16 bit format you must return a 16 bit integer
if ( bpmem . zcontrol . pixel_format == PIXELFMT_RGB565_Z16 ) {
z >>= 8 ;
2010-12-27 03:18:01 +00:00
}
2011-01-10 21:28:02 +00:00
2010-10-22 19:40:05 +00:00
return z ;
2009-11-22 02:37:00 +00:00
}
2010-10-22 19:40:05 +00:00
else if ( type == PEEK_COLOR )
2009-10-08 00:35:47 +00:00
{
2010-10-22 19:40:05 +00:00
// TODO: Can't we directly StretchRect to System buf?
hr = D3D :: dev -> StretchRect ( pEFBSurf , & RectToLock , pBufferRT , NULL , D3DTEXF_NONE );
D3D :: dev -> GetRenderTargetData ( pBufferRT , pSystemBuf );
// EFB data successfully retrieved, now get the pixel data
2009-11-10 12:45:03 +00:00
RectToLock . bottom = 1 ;
RectToLock . left = 0 ;
RectToLock . right = 1 ;
RectToLock . top = 0 ;
2011-01-10 21:28:02 +00:00
2010-10-22 19:40:05 +00:00
D3DLOCKED_RECT drect ;
pSystemBuf -> LockRect ( & drect , & RectToLock , D3DLOCK_READONLY );
2010-10-24 19:52:52 +00:00
u32 ret = (( u32 * ) drect . pBits )[ 0 ];
2010-10-22 19:40:05 +00:00
pSystemBuf -> UnlockRect ();
2010-10-24 19:52:52 +00:00
// check what to do with the alpha channel (GX_PokeAlphaRead)
PixelEngine :: UPEAlphaReadReg alpha_read_mode ;
2011-01-07 19:51:28 +00:00
PixelEngine :: Read16 (( u16 & ) alpha_read_mode , PE_ALPHAREAD );
2011-01-10 21:28:02 +00:00
2010-12-27 03:18:01 +00:00
if ( bpmem . zcontrol . pixel_format == PIXELFMT_RGBA6_Z24 )
{
ret = RGBA8ToRGBA6ToRGBA8 ( ret );
}
else if ( bpmem . zcontrol . pixel_format == PIXELFMT_RGB565_Z16 )
{
2010-12-27 18:09:03 +00:00
ret = RGBA8ToRGB565ToRGBA8 ( ret );
}
2010-12-27 03:18:01 +00:00
if ( bpmem . zcontrol . pixel_format != PIXELFMT_RGBA6_Z24 )
{
ret |= 0xFF000000 ;
}
2011-01-10 21:28:02 +00:00
2010-10-24 19:52:52 +00:00
if ( alpha_read_mode . ReadMode == 2 ) return ret ; // GX_READ_NONE
else if ( alpha_read_mode . ReadMode == 1 ) return ( ret | 0xFF000000 ); // GX_READ_FF
2010-12-27 03:18:01 +00:00
else return ( ret & 0x00FFFFFF ); // GX_READ_00
2010-10-22 19:40:05 +00:00
}
else //if(type == POKE_COLOR)
{
// TODO: Speed this up by batching pokes?
ResetAPIState ();
2012-02-20 11:51:40 +01:00
D3D :: drawColorQuad ( poke_data ,
2011-05-12 02:14:45 +00:00
( float ) RectToLock . left * 2.f / ( float ) Renderer :: GetTargetWidth () - 1.f ,
- ( float ) RectToLock . top * 2.f / ( float ) Renderer :: GetTargetHeight () + 1.f ,
( float ) RectToLock . right * 2.f / ( float ) Renderer :: GetTargetWidth () - 1.f ,
- ( float ) RectToLock . bottom * 2.f / ( float ) Renderer :: GetTargetHeight () + 1.f );
2010-10-22 19:40:05 +00:00
RestoreAPIState ();
return 0 ;
2009-09-04 17:29:16 +00:00
}
}
2011-05-12 02:14:45 +00:00
// Viewport correction:
// Say you want a viewport at (ix, iy) with size (iw, ih),
// but your viewport must be clamped at (ax, ay) with size (aw, ah).
// Just multiply the projection matrix with the following to get the same
// effect:
// [ (iw/aw) 0 0 ((iw - 2*(ax-ix)) / aw - 1) ]
// [ 0 (ih/ah) 0 ((-ih + 2*(ay-iy)) / ah + 1) ]
// [ 0 0 1 0 ]
// [ 0 0 0 1 ]
static void ViewportCorrectionMatrix ( Matrix44 & result ,
float ix , float iy , float iw , float ih , // Intended viewport ( x , y , width , height )
float ax , float ay , float aw , float ah ) // Actual viewport (x, y, width, height)
{
Matrix44 :: LoadIdentity ( result );
if ( aw == 0.f || ah == 0.f )
return ;
result . data [ 4 * 0 + 0 ] = iw / aw ;
result . data [ 4 * 0 + 3 ] = ( iw - 2.f * ( ax - ix )) / aw - 1.f ;
result . data [ 4 * 1 + 1 ] = ih / ah ;
result . data [ 4 * 1 + 3 ] = ( - ih + 2.f * ( ay - iy )) / ah + 1.f ;
}
2009-02-28 22:10:38 +00:00
// Called from VertexShaderManager
2011-05-12 02:14:45 +00:00
void Renderer :: UpdateViewport ( Matrix44 & vpCorrection )
2009-02-28 22:10:38 +00:00
{
2009-11-23 14:08:08 +00:00
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
2010-02-25 06:12:35 +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
2010-07-11 16:26:46 +00:00
2011-05-12 02:14:45 +00:00
int scissorXOff = bpmem . scissorOffset . x * 2 ;
int scissorYOff = bpmem . scissorOffset . y * 2 ;
2009-09-03 19:24:16 +00:00
2010-12-10 15:54:14 +00:00
// TODO: ceil, floor or just cast to int?
2011-05-12 02:14:45 +00:00
int intendedX = EFBToScaledX (( int ) ceil ( xfregs . viewport . xOrig - xfregs . viewport . wd - scissorXOff ));
int intendedY = EFBToScaledY (( int ) ceil ( xfregs . viewport . yOrig + xfregs . viewport . ht - scissorYOff ));
int intendedWd = EFBToScaledX (( int ) ceil ( 2.0f * xfregs . viewport . wd ));
int intendedHt = EFBToScaledY (( int ) ceil ( - 2.0f * xfregs . viewport . ht ));
if ( intendedWd < 0 )
2009-11-23 14:08:08 +00:00
{
2011-05-12 02:14:45 +00:00
intendedX += intendedWd ;
intendedWd = - intendedWd ;
2009-11-23 14:08:08 +00:00
}
2011-05-12 02:14:45 +00:00
if ( intendedHt < 0 )
2009-11-23 14:08:08 +00:00
{
2011-05-12 02:14:45 +00:00
intendedY += intendedHt ;
intendedHt = - intendedHt ;
2009-11-23 14:08:08 +00:00
}
2011-05-12 02:14:45 +00:00
// In D3D, the viewport rectangle must fit within the render target.
2013-01-16 15:46:11 -05:00
int X = intendedX ;
if ( X < 0 )
X = 0 ;
int Y = intendedY ;
if ( Y < 0 )
Y = 0 ;
int Wd = intendedWd ;
2011-05-12 02:14:45 +00:00
if ( X + Wd > GetTargetWidth ())
Wd = GetTargetWidth () - X ;
2013-01-16 15:46:11 -05:00
int Ht = intendedHt ;
2011-05-12 02:14:45 +00:00
if ( Y + Ht > GetTargetHeight ())
Ht = GetTargetHeight () - Y ;
2011-04-02 11:38:29 +00:00
2011-05-12 02:14:45 +00:00
// If GX viewport is off the render target, we must clamp our viewport
// within the bounds. Use the correction matrix to compensate.
ViewportCorrectionMatrix ( vpCorrection ,
2012-12-23 20:01:58 +13:00
( float ) intendedX , ( float ) intendedY , ( float ) intendedWd , ( float ) intendedHt ,
( float ) X , ( float ) Y , ( float ) Wd , ( float ) Ht );
2010-11-18 02:21:26 +00:00
D3DVIEWPORT9 vp ;
2009-11-20 18:46:30 +00:00
vp . X = X ;
vp . Y = Y ;
2011-05-12 02:14:45 +00:00
vp . Width = Wd ;
vp . Height = Ht ;
2010-01-15 15:52:08 +00:00
2010-07-06 13:14:51 +00:00
// Some games set invalids values for z min and z max so fix them to the max an min alowed and let the shaders do this work
2011-04-11 01:49:32 +00:00
vp . MinZ = 0.0f ; // (xfregs.viewport.farZ - xfregs.viewport.zRange) / 16777216.0f;
vp . MaxZ = 1.0f ; // xfregs.viewport.farZ / 16777216.0f;
2009-02-28 22:10:38 +00:00
D3D :: dev -> SetViewport ( & vp );
2009-09-02 04:10:40 +00:00
}
2009-09-20 03:29:43 +00:00
2010-12-19 22:00:25 +00:00
void Renderer :: ClearScreen ( const EFBRectangle & rc , bool colorEnable , bool alphaEnable , bool zEnable , u32 color , u32 z )
2010-07-06 13:14:51 +00:00
{
2010-11-01 19:13:50 +00:00
// Reset rendering pipeline while keeping color masks and depth buffer settings
ResetAPIState ();
2010-12-20 16:57:29 +00:00
DWORD color_mask = 0 ;
if ( alphaEnable )
color_mask = D3DCOLORWRITEENABLE_ALPHA ;
if ( colorEnable )
color_mask |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE ;
D3D :: ChangeRenderState ( D3DRS_COLORWRITEENABLE , color_mask );
if ( zEnable )
{
D3D :: ChangeRenderState ( D3DRS_ZENABLE , TRUE );
D3D :: ChangeRenderState ( D3DRS_ZWRITEENABLE , TRUE );
2010-11-01 19:13:50 +00:00
D3D :: ChangeRenderState ( D3DRS_ZFUNC , D3DCMP_ALWAYS );
2010-12-20 16:57:29 +00:00
}
else
D3D :: ChangeRenderState ( D3DRS_ZENABLE , FALSE );
2010-11-01 19:13:50 +00:00
2010-12-10 15:54:14 +00:00
// Update the viewport for clearing the target EFB rect
2010-09-30 15:24:34 +00:00
TargetRectangle targetRc = ConvertEFBRectangle ( rc );
2010-02-25 06:12:35 +00:00
D3DVIEWPORT9 vp ;
2010-06-15 21:19:09 +00:00
vp . X = targetRc . left ;
2010-07-06 13:14:51 +00:00
vp . Y = targetRc . top ;
2010-06-15 21:19:09 +00:00
vp . Width = targetRc . GetWidth ();
vp . Height = targetRc . GetHeight ();
2009-11-22 02:37:00 +00:00
vp . MinZ = 0.0 ;
vp . MaxZ = 1.0 ;
2010-07-06 13:14:51 +00:00
D3D :: dev -> SetViewport ( & vp );
2012-02-20 11:51:40 +01:00
D3D :: drawClearQuad ( color , ( z & 0xFFFFFF ) / float ( 0xFFFFFF ), PixelShaderCache :: GetClearProgram (), VertexShaderCache :: GetClearVertexShader ());
2010-11-01 19:13:50 +00:00
RestoreAPIState ();
2009-10-02 21:23:56 +00:00
}
2010-12-27 21:56:20 +00:00
void Renderer :: ReinterpretPixelData ( unsigned int convtype )
{
RECT source ;
2011-05-12 02:14:45 +00:00
SetRect ( & source , 0 , 0 , g_renderer -> GetTargetWidth (), g_renderer -> GetTargetHeight ());
2010-12-27 21:56:20 +00:00
LPDIRECT3DPIXELSHADER9 pixel_shader ;
if ( convtype == 0 ) pixel_shader = PixelShaderCache :: ReinterpRGB8ToRGBA6 ();
else if ( convtype == 2 ) pixel_shader = PixelShaderCache :: ReinterpRGBA6ToRGB8 ();
else
{
2012-01-06 13:45:51 +01:00
ERROR_LOG ( VIDEO , "Trying to reinterpret pixel data with unsupported conversion type %d" , convtype );
2010-12-27 21:56:20 +00:00
return ;
}
// convert data and set the target texture as our new EFB
g_renderer -> ResetAPIState ();
D3D :: dev -> SetRenderTarget ( 0 , FramebufferManager :: GetEFBColorReinterpretSurface ());
2011-01-23 15:29:57 +00:00
D3DVIEWPORT9 vp ;
vp . X = 0 ;
vp . Y = 0 ;
2011-05-12 02:14:45 +00:00
vp . Width = g_renderer -> GetTargetWidth ();
vp . Height = g_renderer -> GetTargetHeight ();
2011-01-23 15:29:57 +00:00
vp . MinZ = 0.0 ;
vp . MaxZ = 1.0 ;
D3D :: dev -> SetViewport ( & vp );
D3D :: ChangeSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_POINT );
2011-05-12 02:14:45 +00:00
D3D :: drawShadedTexQuad ( FramebufferManager :: GetEFBColorTexture (), & source ,
g_renderer -> GetTargetWidth (), g_renderer -> GetTargetHeight (),
g_renderer -> GetTargetWidth (), g_renderer -> GetTargetHeight (),
pixel_shader , VertexShaderCache :: GetSimpleVertexShader ( 0 ));
2010-12-27 21:56:20 +00:00
FramebufferManager :: SwapReinterpretTexture ();
2011-01-23 15:29:57 +00:00
D3D :: RefreshSamplerState ( 0 , D3DSAMP_MINFILTER );
2010-12-27 21:56:20 +00:00
g_renderer -> RestoreAPIState ();
}
2009-10-10 23:36:18 +00:00
void Renderer :: SetBlendMode ( bool forceUpdate )
2010-07-06 13:14:51 +00:00
{
2013-01-13 23:35:07 +01:00
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
bool target_has_alpha = bpmem . zcontrol . pixel_format == PIXELFMT_RGBA6_Z24 ;
const D3DBLEND d3dSrcFactors [ 8 ] =
{
D3DBLEND_ZERO ,
D3DBLEND_ONE ,
D3DBLEND_DESTCOLOR ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_SRCALPHA ,
D3DBLEND_INVSRCALPHA ,
( target_has_alpha ) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE ,
( target_has_alpha ) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO
};
const D3DBLEND d3dDestFactors [ 8 ] =
{
D3DBLEND_ZERO ,
D3DBLEND_ONE ,
D3DBLEND_SRCCOLOR ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_SRCALPHA ,
D3DBLEND_INVSRCALPHA ,
( target_has_alpha ) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE ,
( target_has_alpha ) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO
};
2010-11-30 21:44:54 +00:00
if ( bpmem . blendmode . logicopenable && ! forceUpdate )
2009-12-07 18:48:31 +00:00
return ;
2010-12-28 12:46:00 +00:00
2010-07-06 13:14:51 +00:00
if ( bpmem . blendmode . subtract && bpmem . blendmode . blendenable )
2010-06-24 15:58:06 +00:00
{
D3D :: SetRenderState ( D3DRS_ALPHABLENDENABLE , true );
D3D :: SetRenderState ( D3DRS_BLENDOP , D3DBLENDOP_REVSUBTRACT );
D3D :: SetRenderState ( D3DRS_SRCBLEND , d3dSrcFactors [ 1 ]);
D3D :: SetRenderState ( D3DRS_DESTBLEND , d3dDestFactors [ 1 ]);
2010-07-06 13:14:51 +00:00
}
else
2010-06-24 15:58:06 +00:00
{
2013-01-13 23:35:07 +01:00
D3D :: SetRenderState ( D3DRS_ALPHABLENDENABLE , bpmem . blendmode . blendenable );
if ( bpmem . blendmode . blendenable )
2010-06-24 15:58:06 +00:00
{
D3D :: SetRenderState ( D3DRS_BLENDOP , D3DBLENDOP_ADD );
D3D :: SetRenderState ( D3DRS_SRCBLEND , d3dSrcFactors [ bpmem . blendmode . srcfactor ]);
D3D :: SetRenderState ( D3DRS_DESTBLEND , d3dDestFactors [ bpmem . blendmode . dstfactor ]);
2010-07-06 13:14:51 +00:00
}
}
2009-10-10 23:36:18 +00:00
}
2009-10-02 21:23:56 +00:00
2010-11-18 02:21:26 +00:00
bool Renderer :: SaveScreenshot ( const std :: string & filename , const TargetRectangle & dst_rect )
{
HRESULT hr = D3D :: dev -> GetRenderTargetData ( D3D :: GetBackBufferSurface (), ScreenShootMEMSurface );
if ( FAILED ( hr ))
{
PanicAlert ( "Error dumping surface data." );
return false ;
}
hr = PD3DXSaveSurfaceToFileA ( filename . c_str (), D3DXIFF_PNG , ScreenShootMEMSurface , NULL , dst_rect . AsRECT ());
if ( FAILED ( hr ))
{
PanicAlert ( "Error saving screen." );
return false ;
}
return true ;
}
2010-09-28 02:15:02 +00:00
// This function has the final picture. We adjust the aspect ratio here.
2010-12-27 03:18:01 +00:00
void Renderer :: Swap ( u32 xfbAddr , FieldType field , u32 fbWidth , u32 fbHeight , const EFBRectangle & rc , float Gamma )
2009-09-20 03:29:43 +00:00
{
2012-09-28 23:19:50 +02:00
if ( g_bSkipCurrentFrame || ( ! XFBWrited && ! g_ActiveConfig . RealXFBEnabled ()) || ! fbWidth || ! fbHeight )
2010-03-28 23:51:32 +00:00
{
2013-02-26 20:47:48 -05:00
if ( g_ActiveConfig . bDumpFrames && ! frame_data . empty ())
AVIDump :: AddFrame ( & frame_data [ 0 ], fbWidth , fbHeight );
2011-09-08 15:39:03 +02:00
2011-01-31 01:28:32 +00:00
Core :: Callback_VideoCopiedToXFB ( false );
2010-03-14 18:57:50 +00:00
return ;
2010-03-28 23:51:32 +00:00
}
2010-09-28 02:15:02 +00:00
2010-04-14 13:57:16 +00:00
if ( field == FIELD_LOWER ) xfbAddr -= fbWidth * 2 ;
2010-03-14 18:57:50 +00:00
u32 xfbCount = 0 ;
2010-11-18 02:21:26 +00:00
const XFBSourceBase * const * xfbSourceList = FramebufferManager :: GetXFBSource ( xfbAddr , fbWidth , fbHeight , xfbCount );
2010-07-02 17:09:53 +00:00
if (( ! xfbSourceList || xfbCount == 0 ) && g_ActiveConfig . bUseXFB && ! g_ActiveConfig . bUseRealXFB )
2010-03-14 18:57:50 +00:00
{
2013-02-26 20:47:48 -05:00
if ( g_ActiveConfig . bDumpFrames && ! frame_data . empty ())
AVIDump :: AddFrame ( & frame_data [ 0 ], fbWidth , fbHeight );
2011-09-08 15:39:03 +02:00
2011-01-31 01:28:32 +00:00
Core :: Callback_VideoCopiedToXFB ( false );
2010-03-14 18:57:50 +00:00
return ;
2010-07-06 13:14:51 +00:00
}
2010-03-14 18:57:50 +00:00
2010-09-30 15:24:34 +00:00
ResetAPIState ();
2010-11-18 02:21:26 +00:00
2010-09-23 02:17:48 +00:00
if ( g_ActiveConfig . bAnaglyphStereo )
{
2010-11-10 16:43:27 +00:00
static bool RightFrame = false ;
2010-09-23 02:17:48 +00:00
if ( RightFrame )
{
D3D :: SetRenderState ( D3DRS_COLORWRITEENABLE , D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN );
VertexShaderManager :: ResetView ();
VertexShaderManager :: TranslateView ( - 0.001f * g_ActiveConfig . iAnaglyphStereoSeparation , 0.0f );
2010-12-10 15:54:14 +00:00
VertexShaderManager :: RotateView ( - 0.0001f * g_ActiveConfig . iAnaglyphFocalAngle , 0.0f );
2010-09-23 02:17:48 +00:00
RightFrame = false ;
}
else
{
D3D :: SetRenderState ( D3DRS_COLORWRITEENABLE , D3DCOLORWRITEENABLE_RED );
VertexShaderManager :: ResetView ();
VertexShaderManager :: TranslateView ( 0.001f * g_ActiveConfig . iAnaglyphStereoSeparation , 0.0f );
2010-12-10 15:54:14 +00:00
VertexShaderManager :: RotateView ( 0.0001f * g_ActiveConfig . iAnaglyphFocalAngle , 0.0f );
2010-09-23 02:17:48 +00:00
RightFrame = true ;
}
}
2010-09-28 02:15:02 +00:00
// Prepare to copy the XFBs to our backbuffer
2010-03-14 18:57:50 +00:00
D3D :: dev -> SetDepthStencilSurface ( NULL );
D3D :: dev -> SetRenderTarget ( 0 , D3D :: GetBackBufferSurface ());
2012-09-29 00:04:55 +02:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height );
2010-03-14 18:57:50 +00:00
D3DVIEWPORT9 vp ;
2010-09-30 15:24:34 +00:00
// Clear full target screen (edges, borders etc)
2010-11-10 16:43:27 +00:00
if ( g_ActiveConfig . bAnaglyphStereo ) {
// use a clear quad to keep old red or blue/green data
vp . X = 0 ;
vp . Y = 0 ;
vp . Width = s_backbuffer_width ;
vp . Height = s_backbuffer_height ;
vp . MinZ = 0.0f ;
vp . MaxZ = 1.0f ;
D3D :: dev -> SetViewport ( & vp );
2012-02-20 11:51:40 +01:00
D3D :: drawClearQuad ( 0 , 1.0 , PixelShaderCache :: GetClearProgram (), VertexShaderCache :: GetClearVertexShader ());
2010-11-10 16:43:27 +00:00
}
else
{
D3D :: dev -> Clear ( 0 , NULL , D3DCLEAR_TARGET , D3DCOLOR_XRGB ( 0 , 0 , 0 ), 1.0f , 0 );
}
2010-03-14 18:57:50 +00:00
2013-01-16 15:46:11 -05:00
int X = GetTargetRectangle (). left ;
int Y = GetTargetRectangle (). top ;
int Width = GetTargetRectangle (). right - GetTargetRectangle (). left ;
int Height = GetTargetRectangle (). bottom - GetTargetRectangle (). top ;
2010-09-30 15:24:34 +00:00
2010-12-10 15:54:14 +00:00
// Sanity check
2013-01-16 15:46:11 -05:00
if ( X < 0 ) X = 0 ;
if ( Y < 0 ) Y = 0 ;
2010-03-14 18:57:50 +00:00
if ( X > s_backbuffer_width ) X = s_backbuffer_width ;
if ( Y > s_backbuffer_height ) Y = s_backbuffer_height ;
2013-01-16 15:46:11 -05:00
if ( Width < 0 ) Width = 0 ;
if ( Height < 0 ) Height = 0 ;
2010-03-14 18:57:50 +00:00
if ( Width > ( s_backbuffer_width - X )) Width = s_backbuffer_width - X ;
if ( Height > ( s_backbuffer_height - Y )) Height = s_backbuffer_height - Y ;
2010-09-30 15:24:34 +00:00
2010-03-14 18:57:50 +00:00
vp . X = X ;
vp . Y = Y ;
vp . Width = Width ;
vp . Height = Height ;
vp . MinZ = 0.0f ;
vp . MaxZ = 1.0f ;
D3D :: dev -> SetViewport ( & vp );
D3D :: ChangeSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR );
D3D :: ChangeSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR );
2010-11-14 23:31:53 +00:00
const XFBSourceBase * xfbSource = NULL ;
2010-09-30 15:24:34 +00:00
2010-07-02 17:09:53 +00:00
if ( g_ActiveConfig . bUseXFB )
2010-03-14 18:57:50 +00:00
{
2010-07-02 17:09:53 +00:00
// draw each xfb source
2010-09-30 15:24:34 +00:00
// Render to the real buffer now.
2010-07-02 17:09:53 +00:00
for ( u32 i = 0 ; i < xfbCount ; ++ i )
2010-03-14 18:57:50 +00:00
{
2010-09-28 02:15:02 +00:00
xfbSource = xfbSourceList [ i ];
2010-09-30 15:24:34 +00:00
2010-07-02 17:09:53 +00:00
MathUtil :: Rectangle < float > sourceRc ;
2010-05-24 14:20:19 +00:00
2010-07-02 17:09:53 +00:00
sourceRc . left = 0 ;
sourceRc . top = 0 ;
2010-12-10 15:54:14 +00:00
sourceRc . right = ( float ) xfbSource -> texWidth ;
sourceRc . bottom = ( float ) xfbSource -> texHeight ;
2010-03-14 18:57:50 +00:00
2010-07-02 17:09:53 +00:00
MathUtil :: Rectangle < float > drawRc ;
2012-09-28 23:21:09 +02:00
if ( g_ActiveConfig . bUseRealXFB )
{
drawRc . top = - 1 ;
drawRc . bottom = 1 ;
drawRc . left = - 1 ;
drawRc . right = 1 ;
}
else
2010-03-14 18:57:50 +00:00
{
2010-07-02 17:09:53 +00:00
// use virtual xfb with offset
int xfbHeight = xfbSource -> srcHeight ;
int xfbWidth = xfbSource -> srcWidth ;
int hOffset = (( s32 ) xfbSource -> srcAddr - ( s32 ) xfbAddr ) / (( s32 ) fbWidth * 2 );
2010-03-14 18:57:50 +00:00
2010-09-28 02:15:02 +00:00
drawRc . bottom = 1.0f - ( 2.0f * ( hOffset ) / ( float ) fbHeight );
drawRc . top = 1.0f - ( 2.0f * ( hOffset + xfbHeight ) / ( float ) fbHeight );
2010-07-02 17:09:53 +00:00
drawRc . left = - ( xfbWidth / ( float ) fbWidth );
drawRc . right = ( xfbWidth / ( float ) fbWidth );
2010-09-30 15:24:34 +00:00
// The following code disables auto stretch. Kept for reference.
// scale draw area for a 1 to 1 pixel mapping with the draw target
2012-09-29 00:04:55 +02:00
//float vScale = (float)fbHeight / (float)GetTargetRectangle().GetHeight();
//float hScale = (float)fbWidth / (float)GetTargetRectangle().GetWidth();
2010-09-30 15:24:34 +00:00
//drawRc.top *= vScale;
//drawRc.bottom *= vScale;
//drawRc.left *= hScale;
//drawRc.right *= hScale;
2010-07-02 17:09:53 +00:00
}
2010-03-14 18:57:50 +00:00
2010-11-14 23:31:53 +00:00
xfbSource -> Draw ( sourceRc , drawRc , Width , Height );
2010-07-02 17:09:53 +00:00
}
}
else
{
2010-09-30 15:24:34 +00:00
TargetRectangle targetRc = ConvertEFBRectangle ( rc );
2010-11-14 23:31:53 +00:00
LPDIRECT3DTEXTURE9 read_texture = FramebufferManager :: GetEFBColorTexture ();
2011-05-12 02:14:45 +00:00
D3D :: drawShadedTexQuad ( read_texture , targetRc . AsRECT (),
Renderer :: GetTargetWidth (), Renderer :: GetTargetHeight (),
Width , Height ,
PixelShaderCache :: GetColorCopyProgram ( g_ActiveConfig . iMultisampleMode ),
VertexShaderCache :: GetSimpleVertexShader ( g_ActiveConfig . iMultisampleMode ), Gamma );
2011-01-07 19:23:57 +00:00
2010-03-14 18:57:50 +00:00
}
D3D :: RefreshSamplerState ( 0 , D3DSAMP_MINFILTER );
2010-07-06 13:14:51 +00:00
D3D :: RefreshSamplerState ( 0 , D3DSAMP_MAGFILTER );
2010-09-30 15:24:34 +00:00
2010-09-23 02:17:48 +00:00
if ( g_ActiveConfig . bAnaglyphStereo )
{
DWORD color_mask = D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE ;
D3D :: SetRenderState ( D3DRS_COLORWRITEENABLE , color_mask );
}
2010-09-30 15:24:34 +00:00
2010-03-14 18:57:50 +00:00
vp . X = 0 ;
vp . Y = 0 ;
vp . Width = s_backbuffer_width ;
vp . Height = s_backbuffer_height ;
vp . MinZ = 0.0f ;
vp . MaxZ = 1.0f ;
D3D :: dev -> SetViewport ( & vp );
2010-09-30 15:24:34 +00:00
// Save screenshot
2010-09-28 02:15:02 +00:00
if ( s_bScreenshot )
2010-03-14 18:57:50 +00:00
{
2011-03-05 06:11:26 +00:00
std :: lock_guard < std :: mutex > lk ( s_criticalScreenshot );
2012-09-29 00:04:55 +02:00
SaveScreenshot ( s_sScreenshotName , GetTargetRectangle ());
2010-03-14 18:57:50 +00:00
s_bScreenshot = false ;
}
2011-09-08 15:39:03 +02:00
// Dump frames
static int w = 0 , h = 0 ;
2010-07-06 13:14:51 +00:00
if ( g_ActiveConfig . bDumpFrames )
2010-03-14 18:57:50 +00:00
{
2011-09-08 15:39:03 +02:00
static int s_recordWidth ;
static int s_recordHeight ;
2010-07-09 20:56:16 +00:00
HRESULT hr = D3D :: dev -> GetRenderTargetData ( D3D :: GetBackBufferSurface (), ScreenShootMEMSurface );
2011-09-08 15:39:03 +02:00
if ( ! bLastFrameDumped )
2010-03-14 18:57:50 +00:00
{
2012-09-29 00:04:55 +02:00
s_recordWidth = GetTargetRectangle (). GetWidth ();
s_recordHeight = GetTargetRectangle (). GetHeight ();
2011-09-08 17:09:24 +02:00
bAVIDumping = AVIDump :: Start ( EmuWindow :: GetParentWnd (), s_recordWidth , s_recordHeight );
if ( ! bAVIDumping )
2010-03-14 18:57:50 +00:00
{
PanicAlert ( "Error dumping frames to AVI." );
2010-07-06 13:14:51 +00:00
}
else
2010-03-14 18:57:50 +00:00
{
char msg [ 255 ];
2011-02-28 20:40:15 +00:00
sprintf_s ( msg , 255 , "Dumping Frames to \" %sframedump0.avi \" (%dx%d RGB24)" ,
File :: GetUserPath ( D_DUMPFRAMES_IDX ). c_str (), s_recordWidth , s_recordHeight );
2010-03-14 18:57:50 +00:00
OSD :: AddMessage ( msg , 2000 );
}
}
2011-09-08 17:09:24 +02:00
if ( bAVIDumping )
2010-03-14 18:57:50 +00:00
{
D3DLOCKED_RECT rect ;
2012-09-29 00:04:55 +02:00
if ( SUCCEEDED ( ScreenShootMEMSurface -> LockRect ( & rect , GetTargetRectangle (). AsRECT (), D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY )))
2010-03-14 18:57:50 +00:00
{
2013-02-26 20:47:48 -05:00
if ( frame_data . empty () || w != s_recordWidth || h != s_recordHeight )
2011-02-11 18:59:42 +00:00
{
2013-02-26 20:47:48 -05:00
frame_data . resize ( 3 * s_recordWidth * s_recordHeight );
2011-02-11 18:59:42 +00:00
w = s_recordWidth ;
h = s_recordHeight ;
}
2013-02-26 20:47:48 -05:00
formatBufferDump (( const u8 * ) rect . pBits , & frame_data [ 0 ], s_recordWidth , s_recordHeight , rect . Pitch );
AVIDump :: AddFrame ( & frame_data [ 0 ], fbWidth , fbHeight );
2010-03-14 18:57:50 +00:00
ScreenShootMEMSurface -> UnlockRect ();
}
}
2011-09-08 15:39:03 +02:00
bLastFrameDumped = true ;
2010-07-06 13:14:51 +00:00
}
else
2010-03-14 18:57:50 +00:00
{
2011-09-08 17:09:24 +02:00
if ( bLastFrameDumped && bAVIDumping )
2010-03-14 18:57:50 +00:00
{
2013-02-26 20:47:48 -05:00
std :: vector < u8 > (). swap ( frame_data );
w = h = 0 ;
2010-03-14 18:57:50 +00:00
AVIDump :: Stop ();
2011-09-08 17:09:24 +02:00
bAVIDumping = false ;
2010-09-28 02:15:02 +00:00
OSD :: AddMessage ( "Stop dumping frames to AVI" , 2000 );
2010-03-14 18:57:50 +00:00
}
2011-09-08 15:39:03 +02:00
bLastFrameDumped = false ;
2010-03-14 18:57:50 +00:00
}
// Finish up the current frame, print some stats
if ( g_ActiveConfig . bShowFPS )
{
char fps [ 20 ];
StringCchPrintfA ( fps , 20 , "FPS: %d \n " , s_fps );
2011-02-17 09:12:36 +00:00
D3D :: font . DrawTextScaled ( 0 , 0 , 20 , 20 , 0.0f , 0xFF00FFFF , fps );
}
2012-11-14 16:21:54 -05:00
if ( SConfig :: GetInstance (). m_ShowLag )
2012-11-11 17:57:06 -05:00
{
char lag [ 10 ];
2012-12-06 20:25:07 -05:00
StringCchPrintfA ( lag , 1000 , "Lag: %llu \n " , Movie :: g_currentLagCount );
2012-11-11 17:57:06 -05:00
D3D :: font . DrawTextScaled ( 0 , 18 , 20 , 20 , 0.0f , 0xFF00FFFF , lag );
}
2011-02-17 09:12:36 +00:00
if ( g_ActiveConfig . bShowInputDisplay )
{
char inputDisplay [ 1000 ];
2011-06-24 06:50:50 +00:00
StringCchPrintfA ( inputDisplay , 1000 , Movie :: GetInputDisplay (). c_str ());
2012-11-11 17:57:06 -05:00
D3D :: font . DrawTextScaled ( 0 , 36 , 20 , 20 , 0.0f , 0xFF00FFFF , inputDisplay );
2010-03-14 18:57:50 +00:00
}
2012-11-11 17:57:06 -05:00
2010-03-14 18:57:50 +00:00
Renderer :: DrawDebugText ();
if ( g_ActiveConfig . bOverlayStats )
{
Statistics :: ToString ( st );
2012-11-11 17:57:06 -05:00
D3D :: font . DrawTextScaled ( 0 , 36 , 20 , 20 , 0.0f , 0xFF00FFFF , st );
2010-03-14 18:57:50 +00:00
}
else if ( g_ActiveConfig . bOverlayProjStats )
{
Statistics :: ToStringProj ( st );
2012-11-12 11:39:33 -05:00
D3D :: font . DrawTextScaled ( 0 , 36 , 20 , 20 , 0.0f , 0xFF00FFFF , st );
2010-03-14 18:57:50 +00:00
}
OSD :: DrawMessages ();
D3D :: EndFrame ();
2012-10-04 05:41:02 +02:00
++ frameCount ;
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_FRAME , true );
2010-08-29 23:08:56 +00:00
DLCache :: ProgressiveCleanup ();
2009-09-20 03:29:43 +00:00
TextureCache :: Cleanup ();
2011-12-26 22:04:59 +01:00
// Enable configuration changes
2010-07-06 13:14:51 +00:00
UpdateActiveConfig ();
2012-05-28 11:31:37 +02:00
TextureCache :: OnConfigChanged ( g_ActiveConfig );
2011-01-07 04:57:59 +00:00
2011-01-25 03:30:12 +00:00
SetWindowSize ( fbWidth , fbHeight );
2011-01-07 04:57:59 +00:00
const bool windowResized = CheckForResize ();
2010-09-28 02:15:02 +00:00
2010-03-14 18:57:50 +00:00
bool xfbchanged = false ;
2010-09-28 02:15:02 +00:00
2012-09-28 23:48:18 +02:00
if ( FramebufferManagerBase :: LastXfbWidth () != fbWidth || FramebufferManagerBase :: LastXfbHeight () != fbHeight )
2010-03-14 18:57:50 +00:00
{
xfbchanged = true ;
2012-09-28 23:48:18 +02:00
unsigned int w = ( fbWidth < 1 || fbWidth > MAX_XFB_WIDTH ) ? MAX_XFB_WIDTH : fbWidth ;
unsigned int h = ( fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT ) ? MAX_XFB_HEIGHT : fbHeight ;
FramebufferManagerBase :: SetLastXfbWidth ( w );
FramebufferManagerBase :: SetLastXfbHeight ( h );
2010-03-14 18:57:50 +00:00
}
2009-09-20 03:29:43 +00:00
2010-02-05 21:55:02 +00:00
u32 newAA = g_ActiveConfig . iMultisampleMode ;
2010-09-30 15:24:34 +00:00
2011-01-07 04:57:59 +00:00
if ( xfbchanged || windowResized || s_LastEFBScale != g_ActiveConfig . iEFBScale || s_LastAA != newAA )
2010-07-06 13:14:51 +00:00
{
2010-02-03 22:19:00 +00:00
s_LastAA = newAA ;
2010-03-14 18:57:50 +00:00
2012-09-29 00:04:55 +02:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height );
2010-03-14 18:57:50 +00:00
2013-01-16 15:46:11 -05:00
int SupersampleCoeficient = ( s_LastAA % 3 ) + 1 ;
2010-11-18 02:21:26 +00:00
2010-09-30 15:24:34 +00:00
s_LastEFBScale = g_ActiveConfig . iEFBScale ;
2013-01-16 15:46:11 -05:00
CalculateTargetSize ( s_backbuffer_width , s_backbuffer_height , SupersampleCoeficient );
2010-09-30 15:24:34 +00:00
2010-02-03 22:19:00 +00:00
D3D :: dev -> SetRenderTarget ( 0 , D3D :: GetBackBufferSurface ());
D3D :: dev -> SetDepthStencilSurface ( D3D :: GetBackBufferDepthSurface ());
2011-01-07 04:57:59 +00:00
if ( windowResized )
2010-03-22 00:21:39 +00:00
{
2011-01-31 13:17:57 +00:00
// device objects lost, so recreate all of them
2010-03-22 00:21:39 +00:00
SetupDeviceObjects ();
}
else
{
2011-01-31 13:17:57 +00:00
// just resize the frame buffer
2010-11-14 23:31:53 +00:00
delete g_framebuffer_manager ;
g_framebuffer_manager = new FramebufferManager ;
2010-03-22 00:21:39 +00:00
}
2010-11-14 23:31:53 +00:00
D3D :: dev -> SetRenderTarget ( 0 , FramebufferManager :: GetEFBColorRTSurface ());
D3D :: dev -> SetDepthStencilSurface ( FramebufferManager :: GetEFBDepthRTSurface ());
2011-01-06 16:05:11 +00:00
D3D :: dev -> Clear ( 0 , NULL , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB ( 0 , 0 , 0 ), 1.0f , 0 );
2010-02-03 22:19:00 +00:00
}
2010-08-01 14:43:07 +00:00
if ( XFBWrited )
2012-10-04 05:41:02 +02:00
s_fps = UpdateFPSCounter ();
2009-09-20 03:29:43 +00:00
// Begin new frame
// Set default viewport and scissor, for the clear to work correctly
2010-09-28 02:15:02 +00:00
// New frame
2009-09-20 03:29:43 +00:00
stats . ResetFrame ();
// Flip/present backbuffer to frontbuffer here
D3D :: Present ();
2010-03-14 18:57:50 +00:00
D3D :: BeginFrame ();
2010-09-30 15:24:34 +00:00
RestoreAPIState ();
2010-11-14 23:31:53 +00:00
D3D :: dev -> SetRenderTarget ( 0 , FramebufferManager :: GetEFBColorRTSurface ());
D3D :: dev -> SetDepthStencilSurface ( FramebufferManager :: GetEFBDepthRTSurface ());
2010-03-14 18:57:50 +00:00
VertexShaderManager :: SetViewportChanged ();
2011-01-31 13:17:57 +00:00
2011-01-31 01:28:32 +00:00
Core :: Callback_VideoCopiedToXFB ( XFBWrited || ( g_ActiveConfig . bUseXFB && g_ActiveConfig . bUseRealXFB ));
2010-03-14 18:57:50 +00:00
XFBWrited = false ;
2009-09-20 03:29:43 +00:00
}
2009-11-08 20:35:11 +00:00
2012-08-10 18:57:37 +02:00
void Renderer :: ApplyState ( bool bUseDstAlpha )
2011-01-24 10:42:43 +00:00
{
2012-08-10 18:57:37 +02:00
if ( bUseDstAlpha )
2011-01-24 10:42:43 +00:00
{
2013-01-08 18:33:58 +01:00
// TODO: WTF is this crap? We're enabling color writing regardless of the actual GPU state here...
2011-01-24 10:42:43 +00:00
D3D :: ChangeRenderState ( D3DRS_COLORWRITEENABLE , D3DCOLORWRITEENABLE_ALPHA );
D3D :: ChangeRenderState ( D3DRS_ALPHABLENDENABLE , false );
2012-10-20 10:22:15 -03:00
if ( bpmem . zmode . testenable && bpmem . zmode . updateenable )
{
2012-10-22 19:37:26 -03:00
//This is needed to draw to the correct pixels in multi-pass algorithms
//this avoid z-figthing and grants that you write to the same pixels
//affected by the last pass
2012-10-20 10:22:15 -03:00
D3D :: ChangeRenderState ( D3DRS_ZWRITEENABLE , false );
D3D :: ChangeRenderState ( D3DRS_ZFUNC , D3DCMP_EQUAL );
}
2011-01-24 10:42:43 +00:00
}
}
2012-03-30 01:56:24 +02:00
void Renderer :: RestoreState ()
2011-01-24 10:42:43 +00:00
{
2012-08-10 18:57:37 +02:00
D3D :: RefreshRenderState ( D3DRS_COLORWRITEENABLE );
D3D :: RefreshRenderState ( D3DRS_ALPHABLENDENABLE );
2012-10-20 10:22:15 -03:00
if ( bpmem . zmode . testenable && bpmem . zmode . updateenable )
{
D3D :: RefreshRenderState ( D3DRS_ZWRITEENABLE );
D3D :: RefreshRenderState ( D3DRS_ZFUNC );
}
2011-01-24 10:42:43 +00:00
// TODO: Enable this code. Caused glitches for me however (neobrain)
// for (unsigned int i = 0; i < 8; ++i)
// D3D::dev->SetTexture(i, NULL);
}
2010-09-28 02:15:02 +00:00
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
2009-11-08 20:35:11 +00:00
void Renderer :: ResetAPIState ()
{
2011-02-06 18:43:56 +00:00
D3D :: SetRenderState ( D3DRS_FILLMODE , D3DFILL_SOLID );
2010-01-15 22:07:53 +00:00
D3D :: SetRenderState ( D3DRS_SCISSORTESTENABLE , FALSE );
2010-06-08 02:56:00 +00:00
D3D :: SetRenderState ( D3DRS_CULLMODE , D3DCULL_NONE );
2010-02-25 06:12:35 +00:00
D3D :: SetRenderState ( D3DRS_ALPHABLENDENABLE , FALSE );
D3D :: SetRenderState ( D3DRS_ZENABLE , FALSE );
2010-06-08 02:56:00 +00:00
D3D :: SetRenderState ( D3DRS_ZWRITEENABLE , FALSE );
2010-07-06 13:14:51 +00:00
DWORD color_mask = D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE ;
2010-01-15 22:07:53 +00:00
D3D :: SetRenderState ( D3DRS_COLORWRITEENABLE , color_mask );
2009-11-08 20:35:11 +00:00
}
void Renderer :: RestoreAPIState ()
{
// Gets us back into a more game-like state.
2011-02-06 18:43:56 +00:00
D3D :: SetRenderState ( D3DRS_FILLMODE , g_ActiveConfig . bWireFrame ? D3DFILL_WIREFRAME : D3DFILL_SOLID );
2010-01-15 22:07:53 +00:00
D3D :: SetRenderState ( D3DRS_SCISSORTESTENABLE , TRUE );
2011-05-12 02:14:45 +00:00
VertexShaderManager :: SetViewportChanged ();
2011-09-05 22:04:28 +02:00
BPFunctions :: SetScissor ();
2011-03-04 23:14:21 +00:00
if ( bpmem . zmode . testenable ) {
2010-07-06 13:14:51 +00:00
D3D :: SetRenderState ( D3DRS_ZENABLE , TRUE );
2011-03-04 23:14:21 +00:00
if ( bpmem . zmode . updateenable )
D3D :: SetRenderState ( D3DRS_ZWRITEENABLE , TRUE );
}
2010-02-25 06:12:35 +00:00
SetColorMask ();
2010-01-15 22:07:53 +00:00
SetLogicOpMode ();
2011-02-25 20:24:48 +00:00
SetGenerationMode ();
2009-11-08 20:35:11 +00:00
}
2009-11-23 14:08:08 +00:00
void Renderer :: SetGenerationMode ()
{
2013-01-13 23:35:07 +01:00
const D3DCULL d3dCullModes [ 4 ] =
{
D3DCULL_NONE ,
D3DCULL_CCW ,
D3DCULL_CW ,
D3DCULL_CCW
};
2010-02-25 06:12:35 +00:00
D3D :: SetRenderState ( D3DRS_CULLMODE , d3dCullModes [ bpmem . genMode . cullmode ]);
2009-11-23 14:08:08 +00:00
}
void Renderer :: SetDepthMode ()
{
2013-01-13 23:35:07 +01:00
const D3DCMPFUNC d3dCmpFuncs [ 8 ] =
{
D3DCMP_NEVER ,
D3DCMP_LESS ,
D3DCMP_EQUAL ,
D3DCMP_LESSEQUAL ,
D3DCMP_GREATER ,
D3DCMP_NOTEQUAL ,
D3DCMP_GREATEREQUAL ,
D3DCMP_ALWAYS
};
2009-11-23 14:08:08 +00:00
if ( bpmem . zmode . testenable )
{
D3D :: SetRenderState ( D3DRS_ZENABLE , TRUE );
D3D :: SetRenderState ( D3DRS_ZWRITEENABLE , bpmem . zmode . updateenable );
2010-02-25 06:12:35 +00:00
D3D :: SetRenderState ( D3DRS_ZFUNC , d3dCmpFuncs [ bpmem . zmode . func ]);
2009-11-23 14:08:08 +00:00
}
else
{
2010-09-28 02:15:02 +00:00
// if the test is disabled write is disabled too
2009-11-23 14:08:08 +00:00
D3D :: SetRenderState ( D3DRS_ZENABLE , FALSE );
2011-03-04 23:14:21 +00:00
D3D :: SetRenderState ( D3DRS_ZWRITEENABLE , FALSE );
2010-02-25 06:12:35 +00:00
}
2009-11-23 14:08:08 +00:00
}
2009-11-27 19:42:27 +00:00
void Renderer :: SetLogicOpMode ()
{
2013-01-13 23:35:07 +01:00
// D3D9 doesn't support logic blending, so this is a huge hack
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
const D3DBLENDOP d3dLogicOpop [ 16 ] =
{
D3DBLENDOP_ADD ,
D3DBLENDOP_ADD ,
D3DBLENDOP_SUBTRACT ,
D3DBLENDOP_ADD ,
D3DBLENDOP_REVSUBTRACT ,
D3DBLENDOP_ADD ,
D3DBLENDOP_MAX ,
D3DBLENDOP_ADD ,
D3DBLENDOP_MAX ,
D3DBLENDOP_MAX ,
D3DBLENDOP_ADD ,
D3DBLENDOP_ADD ,
D3DBLENDOP_ADD ,
D3DBLENDOP_ADD ,
D3DBLENDOP_ADD ,
D3DBLENDOP_ADD
};
const D3DBLEND d3dLogicOpSrcFactors [ 16 ] =
{
D3DBLEND_ZERO ,
D3DBLEND_DESTCOLOR ,
D3DBLEND_ONE ,
D3DBLEND_ONE ,
D3DBLEND_DESTCOLOR ,
D3DBLEND_ZERO ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_ONE ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_ONE
};
const D3DBLEND d3dLogicOpDestFactors [ 16 ] =
{
D3DBLEND_ZERO ,
D3DBLEND_ZERO ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_ZERO ,
D3DBLEND_ONE ,
D3DBLEND_ONE ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_ONE ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_SRCCOLOR ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_INVDESTCOLOR ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_ONE ,
D3DBLEND_INVSRCCOLOR ,
D3DBLEND_ONE
};
if ( bpmem . blendmode . logicopenable )
2009-12-07 18:48:31 +00:00
{
2010-06-24 15:58:06 +00:00
D3D :: SetRenderState ( D3DRS_ALPHABLENDENABLE , true );
2010-06-05 01:38:22 +00:00
D3D :: SetRenderState ( D3DRS_BLENDOP , d3dLogicOpop [ bpmem . blendmode . logicmode ]);
2009-12-07 18:48:31 +00:00
D3D :: SetRenderState ( D3DRS_SRCBLEND , d3dLogicOpSrcFactors [ bpmem . blendmode . logicmode ]);
D3D :: SetRenderState ( D3DRS_DESTBLEND , d3dLogicOpDestFactors [ bpmem . blendmode . logicmode ]);
}
else
{
SetBlendMode ( true );
}
2009-11-27 19:42:27 +00:00
}
void Renderer :: SetDitherMode ()
{
2010-07-06 13:14:51 +00:00
D3D :: SetRenderState ( D3DRS_DITHERENABLE , bpmem . blendmode . dither );
2009-11-27 19:42:27 +00:00
}
void Renderer :: SetLineWidth ()
{
// We can't change line width in D3D unless we use ID3DXLine
2011-04-11 01:49:32 +00:00
float fratio = xfregs . viewport . wd != 0 ? Renderer :: EFBToScaledXf ( 1.f ) : 1.0f ;
2010-12-10 16:13:43 +00:00
float psize = bpmem . lineptwidth . linesize * fratio / 6.0f ;
D3D :: SetRenderState ( D3DRS_POINTSIZE , * (( DWORD * ) & psize ));
2009-11-27 19:42:27 +00:00
}
2010-01-12 23:40:30 +00:00
void Renderer :: SetSamplerState ( int stage , int texindex )
2009-11-27 19:42:27 +00:00
{
2013-01-13 23:35:07 +01:00
const D3DTEXTUREFILTERTYPE d3dMipFilters [ 4 ] =
{
D3DTEXF_NONE ,
D3DTEXF_POINT ,
D3DTEXF_LINEAR ,
D3DTEXF_NONE , //reserved
};
const D3DTEXTUREADDRESS d3dClamps [ 4 ] =
{
D3DTADDRESS_CLAMP ,
D3DTADDRESS_WRAP ,
D3DTADDRESS_MIRROR ,
D3DTADDRESS_WRAP //reserved
};
2010-07-06 13:14:51 +00:00
const FourTexUnits & tex = bpmem . tex [ texindex ];
2009-11-27 19:42:27 +00:00
const TexMode0 & tm0 = tex . texMode0 [ stage ];
2010-04-14 13:57:16 +00:00
const TexMode1 & tm1 = tex . texMode1 [ stage ];
2009-11-27 19:42:27 +00:00
D3DTEXTUREFILTERTYPE min , mag , mip ;
if ( g_ActiveConfig . bForceFiltering )
{
min = mag = mip = D3DTEXF_LINEAR ;
}
else
{
min = ( tm0 . min_filter & 4 ) ? D3DTEXF_LINEAR : D3DTEXF_POINT ;
mag = tm0 . mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT ;
2013-01-13 23:35:07 +01:00
mip = d3dMipFilters [ tm0 . min_filter & 3 ];
2009-11-27 19:42:27 +00:00
}
if ( texindex )
2010-07-06 13:14:51 +00:00
stage += 4 ;
2013-01-13 23:35:07 +01:00
2011-02-05 22:32:20 +00:00
if ( mag == D3DTEXF_LINEAR && min == D3DTEXF_LINEAR && g_ActiveConfig . iMaxAnisotropy )
2009-11-27 19:42:27 +00:00
{
min = D3DTEXF_ANISOTROPIC ;
}
D3D :: SetSamplerState ( stage , D3DSAMP_MINFILTER , min );
D3D :: SetSamplerState ( stage , D3DSAMP_MAGFILTER , mag );
D3D :: SetSamplerState ( stage , D3DSAMP_MIPFILTER , mip );
D3D :: SetSamplerState ( stage , D3DSAMP_ADDRESSU , d3dClamps [ tm0 . wrap_s ]);
D3D :: SetSamplerState ( stage , D3DSAMP_ADDRESSV , d3dClamps [ tm0 . wrap_t ]);
2012-08-10 13:24:40 +02:00
2012-08-10 13:27:35 +02:00
float lodbias = ( s32 ) tm0 . lod_bias / 32.0f ;
2010-07-06 13:14:51 +00:00
D3D :: SetSamplerState ( stage , D3DSAMP_MIPMAPLODBIAS , * ( DWORD * ) & lodbias );
2013-02-07 21:44:51 +01:00
D3D :: SetSamplerState ( stage , D3DSAMP_MAXMIPLEVEL , tm1 . min_lod >> 4 );
2009-11-27 19:42:27 +00:00
}
void Renderer :: SetInterlacingMode ()
{
// TODO
}
2010-01-27 22:07:59 +00:00
2011-01-29 20:16:51 +00:00
} // namespace DX9