2009-07-28 15:32:10 -06:00
// Copyright (C) 2003 Dolphin Project.
2009-07-05 20:10:26 -06: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/
# include <cmath>
2010-06-04 19:38:22 -06:00
# include "VideoConfig.h"
2009-07-05 20:10:26 -06:00
# include "Statistics.h"
2010-11-17 19:21:26 -07:00
# include "RenderBase.h"
2009-07-05 20:10:26 -06:00
# include "VideoCommon.h"
# include "PixelShaderManager.h"
2009-10-10 15:19:39 -06:00
# include "PixelEngine.h"
2009-07-05 20:10:26 -06:00
# include "BPFunctions.h"
# include "BPStructs.h"
# include "TextureDecoder.h"
# include "OpcodeDecoding.h"
# include "VertexLoader.h"
# include "VertexShaderManager.h"
2009-07-22 16:50:52 -06:00
# include "Thread.h"
2012-01-29 13:17:22 -07:00
# include "HW/Memmap.h"
2009-07-05 20:10:26 -06:00
using namespace BPFunctions ;
2012-12-21 13:04:53 -07:00
static u32 mapTexAddress ;
static bool mapTexFound ;
static int numWrites ;
2010-08-04 21:24:13 -06:00
2011-10-28 14:12:12 -06:00
extern volatile bool g_bSkipCurrentFrame ;
2010-12-31 00:06:53 -07:00
static const float s_gammaLUT [ ] =
{
1.0f ,
1.7f ,
2.2f ,
1.0f
} ;
2009-07-05 20:10:26 -06:00
void BPInit ( )
{
2010-06-04 19:38:22 -06:00
memset ( & bpmem , 0 , sizeof ( bpmem ) ) ;
bpmem . bpMask = 0xFFFFFF ;
2010-08-04 21:24:13 -06:00
2010-08-05 12:41:02 -06:00
mapTexAddress = 0 ;
numWrites = 0 ;
mapTexFound = false ;
2009-07-05 20:10:26 -06:00
}
2010-12-31 00:06:53 -07:00
void RenderToXFB ( const BPCmd & bp , const EFBRectangle & rc , float yScale , float xfbLines , u32 xfbAddr , const u32 dstWidth , const u32 dstHeight , float gamma )
2009-09-13 11:46:33 -06:00
{
2010-12-31 00:06:53 -07:00
Renderer : : RenderToXFB ( xfbAddr , dstWidth , dstHeight , rc , gamma ) ;
2009-09-13 11:46:33 -06:00
}
2009-07-26 03:52:35 -06:00
void BPWritten ( const BPCmd & bp )
2009-07-05 20:10:26 -06:00
{
2010-06-04 19:38:22 -06:00
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Purpose : Writes to the BP registers
Called : At the end of every : OpcodeDecoding . cpp ExecuteDisplayList > Decode ( ) > LoadBPReg
How It Works : First the pipeline is flushed then update the bpmem with the new value .
Some of the BP cases have to call certain functions while others just update the bpmem .
some bp cases check the changes variable , because they might not have to be updated all the time
NOTE : it seems not all bp cases like checking changes , so calling if ( bp . changes = = 0 ? false : true )
had to be ditched and the games seem to work fine with out it .
NOTE2 : Yet Another Gamecube Documentation calls them Bypass Raster State Registers but possibly completely wrong
NOTE3 : This controls the register groups : RAS1 / 2 , SU , TF , TEV , C / Z , PEC
TODO : Turn into function table . The ( future ) DisplayList ( DL ) jit can then call the functions directly ,
getting rid of dynamic dispatch . Unfortunately , few games use DLs properly - most \
just stuff geometry in them and don ' t put state changes there
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2012-12-21 13:04:53 -07:00
// check for invalid state, else unneeded configuration are built
2012-12-23 05:32:23 -07:00
g_video_backend - > CheckInvalidState ( ) ;
2009-07-05 20:10:26 -06:00
// Debugging only, this lets you skip a bp update
//static int times = 0;
//static bool enable = false;
//switch (bp.address)
//{
//case BPMEM_CONSTANTALPHA:
// {
// if (times-- == 0 && enable)
// return;
// else
// break;
// }
//default: break;
//}
2009-07-22 16:50:52 -06:00
// FIXME: Hangs load-state, but should fix graphic-heavy games state loading
2011-03-05 05:05:58 -07:00
//std::lock_guard<std::mutex> lk(s_bpCritical);
2009-07-22 16:50:52 -06:00
2010-08-05 12:41:02 -06:00
// BEGIN ZTP SPEEDUP HACK CHANGES
// This hunk of code disables the usual pipeline flush for certain BP Writes
// that occur while the minimap is being drawn in Zelda: Twilight Princess.
// This significantly increases speed while in hyrule field. In depth discussion
// on how this Hack came to be can be found at: http://forums.dolphin-emu.com/thread-10638.html
// -fircrestsk8
if ( g_ActiveConfig . bZTPSpeedHack )
{
if ( ! mapTexFound )
{
if ( bp . address ! = BPMEM_TEV_COLOR_ENV & & bp . address ! = BPMEM_TEV_ALPHA_ENV )
numWrites = 0 ;
else if ( + + numWrites > = 100 ) // seem that if 100 consecutive BP writes are called to either of these addresses in ZTP,
{ // then it is safe to assume the map texture address is currently loaded into the BP memory
mapTexAddress = bpmem . tex [ 0 ] . texImage3 [ 0 ] . hex < < 5 ;
mapTexFound = true ;
WARN_LOG ( VIDEO , " \n ZTP map texture found at address %08x \n " , mapTexAddress ) ;
}
FlushPipeline ( ) ;
}
else if ( ( bpmem . tex [ 0 ] . texImage3 [ 0 ] . hex < < 5 ) ! = mapTexAddress | |
bpmem . tevorders [ 0 ] . getEnable ( 0 ) = = 0 | |
bp . address = = BPMEM_TREF )
{
FlushPipeline ( ) ;
}
} // END ZTP SPEEDUP HACK
2012-05-18 15:13:53 -06:00
else
{
2012-05-20 12:56:03 -06:00
if ( ( ( s32 * ) & bpmem ) [ bp . address ] = = bp . newvalue )
2012-05-18 15:13:53 -06:00
{
2012-05-20 12:56:03 -06:00
if ( ! ( bp . address = = BPMEM_TRIGGER_EFB_COPY
| | bp . address = = BPMEM_CLEARBBOX1
| | bp . address = = BPMEM_CLEARBBOX2
| | bp . address = = BPMEM_SETDRAWDONE
| | bp . address = = BPMEM_PE_TOKEN_ID
| | bp . address = = BPMEM_PE_TOKEN_INT_ID
| | bp . address = = BPMEM_LOADTLUT0
| | bp . address = = BPMEM_LOADTLUT1
| | bp . address = = BPMEM_TEXINVALIDATE
| | bp . address = = BPMEM_PRELOAD_MODE ) )
{
return ;
}
2012-05-18 15:13:53 -06:00
}
2012-05-20 12:56:03 -06:00
FlushPipeline ( ) ;
2012-05-18 15:13:53 -06:00
}
2010-08-04 21:24:13 -06:00
2010-06-04 19:38:22 -06:00
( ( u32 * ) & bpmem ) [ bp . address ] = bp . newvalue ;
2009-07-05 20:10:26 -06:00
switch ( bp . address )
{
case BPMEM_GENMODE : // Set the Generation Mode
{
2010-06-04 19:38:22 -06:00
PRIM_LOG ( " genmode: texgen=%d, col=%d, ms_en=%d, tev=%d, cullmode=%d, ind=%d, zfeeze=%d " ,
2009-07-05 20:10:26 -06:00
bpmem . genMode . numtexgens , bpmem . genMode . numcolchans ,
bpmem . genMode . ms_en , bpmem . genMode . numtevstages + 1 , bpmem . genMode . cullmode ,
bpmem . genMode . numindstages , bpmem . genMode . zfreeze ) ;
2012-01-01 13:46:02 -07:00
SetGenerationMode ( ) ;
2009-07-05 20:10:26 -06:00
break ;
}
case BPMEM_IND_MTXA : // Index Matrix Changed
case BPMEM_IND_MTXB :
case BPMEM_IND_MTXC :
case BPMEM_IND_MTXA + 3 :
case BPMEM_IND_MTXB + 3 :
case BPMEM_IND_MTXC + 3 :
case BPMEM_IND_MTXA + 6 :
case BPMEM_IND_MTXB + 6 :
case BPMEM_IND_MTXC + 6 :
PixelShaderManager : : SetIndMatrixChanged ( ( bp . address - BPMEM_IND_MTXA ) / 3 ) ;
break ;
case BPMEM_RAS1_SS0 : // Index Texture Coordinate Scale 0
2010-06-04 19:38:22 -06:00
PixelShaderManager : : SetIndTexScaleChanged ( 0x03 ) ;
2009-07-05 20:10:26 -06:00
case BPMEM_RAS1_SS1 : // Index Texture Coordinate Scale 1
2010-06-04 19:38:22 -06:00
PixelShaderManager : : SetIndTexScaleChanged ( 0x0c ) ;
2009-07-05 20:10:26 -06:00
break ;
2009-07-26 03:52:35 -06:00
// ----------------
// Scissor Control
// ----------------
2009-07-05 20:10:26 -06:00
case BPMEM_SCISSORTL : // Scissor Rectable Top, Left
case BPMEM_SCISSORBR : // Scissor Rectable Bottom, Right
case BPMEM_SCISSOROFFSET : // Scissor Offset
2011-09-05 14:04:28 -06:00
SetScissor ( ) ;
2009-07-05 20:10:26 -06:00
break ;
case BPMEM_LINEPTWIDTH : // Line Width
2012-01-01 13:46:02 -07:00
SetLineWidth ( ) ;
2009-07-05 20:10:26 -06:00
break ;
case BPMEM_ZMODE : // Depth Control
PRIM_LOG ( " zmode: test=%d, func=%d, upd=%d " , bpmem . zmode . testenable , bpmem . zmode . func ,
bpmem . zmode . updateenable ) ;
2012-01-01 13:46:02 -07:00
SetDepthMode ( ) ;
2009-07-05 20:10:26 -06:00
break ;
case BPMEM_BLENDMODE : // Blending Control
{
if ( bp . changes & 0xFFFF )
{
PRIM_LOG ( " blendmode: en=%d, open=%d, colupd=%d, alphaupd=%d, dst=%d, src=%d, sub=%d, mode=%d " ,
bpmem . blendmode . blendenable , bpmem . blendmode . logicopenable , bpmem . blendmode . colorupdate , bpmem . blendmode . alphaupdate ,
bpmem . blendmode . dstfactor , bpmem . blendmode . srcfactor , bpmem . blendmode . subtract , bpmem . blendmode . logicmode ) ;
// Set LogicOp Blending Mode
if ( bp . changes & 2 )
2012-01-01 13:46:02 -07:00
SetLogicOpMode ( ) ;
2009-07-05 20:10:26 -06:00
// Set Dithering Mode
if ( bp . changes & 4 )
2012-01-01 13:46:02 -07:00
SetDitherMode ( ) ;
2009-07-05 20:10:26 -06:00
// Set Blending Mode
if ( bp . changes & 0xFE1 )
2012-01-01 13:46:02 -07:00
SetBlendMode ( ) ;
2009-07-05 20:10:26 -06:00
// Set Color Mask
if ( bp . changes & 0x18 )
2012-01-01 13:46:02 -07:00
SetColorMask ( ) ;
2009-07-05 20:10:26 -06:00
}
break ;
}
case BPMEM_CONSTANTALPHA : // Set Destination Alpha
{
PRIM_LOG ( " constalpha: alp=%d, en=%d " , bpmem . dstalpha . alpha , bpmem . dstalpha . enable ) ;
PixelShaderManager : : SetDestAlpha ( bpmem . dstalpha ) ;
break ;
}
// This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); End();)
// Triggers an interrupt on the PPC side so that the game knows when the GPU has finished drawing.
// Tokens are similar.
2010-06-04 19:38:22 -06:00
case BPMEM_SETDRAWDONE :
2009-07-05 20:10:26 -06:00
switch ( bp . newvalue & 0xFF )
2010-06-04 19:38:22 -06:00
{
case 0x02 :
PixelEngine : : SetFinish ( ) ; // may generate interrupt
DEBUG_LOG ( VIDEO , " GXSetDrawDone SetPEFinish (value: 0x%02X) " , ( bp . newvalue & 0xFFFF ) ) ;
break ;
default :
WARN_LOG ( VIDEO , " GXSetDrawDone ??? (value 0x%02X) " , ( bp . newvalue & 0xFFFF ) ) ;
break ;
}
break ;
2009-07-05 20:10:26 -06:00
case BPMEM_PE_TOKEN_ID : // Pixel Engine Token ID
2011-02-01 21:40:27 -07:00
PixelEngine : : SetToken ( static_cast < u16 > ( bp . newvalue & 0xFFFF ) , false ) ;
2010-06-04 19:38:22 -06:00
DEBUG_LOG ( VIDEO , " SetPEToken 0x%04x " , ( bp . newvalue & 0xFFFF ) ) ;
break ;
case BPMEM_PE_TOKEN_INT_ID : // Pixel Engine Interrupt Token ID
2011-02-01 21:40:27 -07:00
PixelEngine : : SetToken ( static_cast < u16 > ( bp . newvalue & 0xFFFF ) , true ) ;
2010-06-04 19:38:22 -06:00
DEBUG_LOG ( VIDEO , " SetPEToken + INT 0x%04x " , ( bp . newvalue & 0xFFFF ) ) ;
break ;
2009-07-05 20:10:26 -06:00
// ------------------------
// EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to XFB as YUYV.
// It can also optionally clear the EFB while copying from it. To emulate this, we of course copy first and clear afterwards.
2010-06-04 19:38:22 -06:00
case BPMEM_TRIGGER_EFB_COPY : // Copy EFB Region or Render to the XFB or Clear the screen.
2009-07-05 20:10:26 -06:00
{
// The bottom right is within the rectangle
// The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function
2009-07-14 18:51:24 -06:00
EFBRectangle rc ;
rc . left = ( int ) bpmem . copyTexSrcXY . x ;
rc . top = ( int ) bpmem . copyTexSrcXY . y ;
2010-12-18 11:23:22 -07:00
// Here Width+1 like Height, otherwise some textures are corrupted already since the native resolution.
2009-07-14 18:51:24 -06:00
rc . right = ( int ) ( bpmem . copyTexSrcXY . x + bpmem . copyTexSrcWH . x + 1 ) ;
rc . bottom = ( int ) ( bpmem . copyTexSrcXY . y + bpmem . copyTexSrcWH . y + 1 ) ;
2009-10-10 15:19:39 -06:00
UPE_Copy PE_copy = bpmem . triggerEFBCopy ;
2009-07-05 20:10:26 -06:00
// Check if we are to copy from the EFB or draw to the XFB
if ( PE_copy . copy_to_xfb = = 0 )
{
2010-06-04 19:38:22 -06:00
if ( GetConfig ( CONFIG_SHOWEFBREGIONS ) )
2009-07-05 20:10:26 -06:00
stats . efb_regions . push_back ( rc ) ;
2011-02-26 16:41:02 -07:00
CopyEFB ( bpmem . copyTexDest < < 5 , PE_copy . tp_realFormat ( ) ,
bpmem . zcontrol . pixel_format , rc , PE_copy . intensity_fmt ,
PE_copy . half_scale ) ;
2009-07-05 20:10:26 -06:00
}
else
{
// We should be able to get away with deactivating the current bbox tracking
// here. Not sure if there's a better spot to put this.
// the number of lines copied is determined by the y scale * source efb height
2011-10-25 18:19:10 -06:00
2010-12-05 09:15:01 -07:00
PixelEngine : : bbox_active = false ;
2009-07-18 14:38:35 -06:00
float yScale ;
2009-07-19 02:24:30 -06:00
if ( PE_copy . scale_invert )
2009-07-18 14:38:35 -06:00
yScale = 256.0f / ( float ) bpmem . dispcopyyscale ;
else
yScale = ( float ) bpmem . dispcopyyscale / 256.0f ;
float xfbLines = ( ( bpmem . copyTexSrcWH . y + 1.0f ) * yScale ) ;
2009-07-19 05:03:31 -06:00
if ( ( u32 ) xfbLines > MAX_XFB_HEIGHT )
2009-07-18 14:38:35 -06:00
{
2009-09-02 12:55:36 -06:00
INFO_LOG ( VIDEO , " Tried to scale EFB to too many XFB lines (%f) " , xfbLines ) ;
2009-07-18 14:38:35 -06:00
xfbLines = MAX_XFB_HEIGHT ;
}
2009-07-14 18:51:24 -06:00
RenderToXFB ( bp , rc , yScale , xfbLines ,
2009-07-05 20:10:26 -06:00
bpmem . copyTexDest < < 5 ,
2009-07-18 14:38:35 -06:00
bpmem . copyMipMapStrideChannels < < 4 ,
2010-12-31 00:06:53 -07:00
( u32 ) xfbLines ,
s_gammaLUT [ PE_copy . gamma ] ) ;
2009-07-05 20:10:26 -06:00
}
2009-09-13 15:18:04 -06:00
// Clear the rectangular region after copying it.
2009-07-05 20:10:26 -06:00
if ( PE_copy . clear )
2009-09-13 15:18:04 -06:00
{
2012-01-01 13:46:02 -07:00
ClearScreen ( rc ) ;
2009-09-13 15:18:04 -06:00
}
2009-07-05 20:10:26 -06:00
break ;
}
2009-12-28 12:13:06 -07:00
case BPMEM_LOADTLUT0 : // This one updates bpmem.tlutXferSrc, no need to do anything here.
break ;
case BPMEM_LOADTLUT1 : // Load a Texture Look Up Table
2010-06-04 19:38:22 -06:00
{
u32 tlutTMemAddr = ( bp . newvalue & 0x3FF ) < < 9 ;
u32 tlutXferCount = ( bp . newvalue & 0x1FFC00 ) > > 5 ;
2009-07-05 20:10:26 -06:00
u8 * ptr = 0 ;
2010-06-04 19:38:22 -06:00
// TODO - figure out a cleaner way.
2009-07-05 20:10:26 -06:00
if ( GetConfig ( CONFIG_ISWII ) )
2012-01-29 13:17:22 -07:00
ptr = GetPointer ( bpmem . tmem_config . tlut_src < < 5 ) ;
2009-07-05 20:10:26 -06:00
else
2012-01-29 13:17:22 -07:00
ptr = GetPointer ( ( bpmem . tmem_config . tlut_src & 0xFFFFF ) < < 5 ) ;
2009-07-05 20:10:26 -06:00
if ( ptr )
memcpy_gc ( texMem + tlutTMemAddr , ptr , tlutXferCount ) ;
else
2012-01-29 13:17:22 -07:00
PanicAlert ( " Invalid palette pointer %08x %08x %08x " , bpmem . tmem_config . tlut_src , bpmem . tmem_config . tlut_src < < 5 , ( bpmem . tmem_config . tlut_src & 0xFFFFF ) < < 5 ) ;
2009-07-05 20:10:26 -06:00
break ;
2010-06-04 19:38:22 -06:00
}
2009-07-05 20:10:26 -06:00
case BPMEM_FOGRANGE : // Fog Settings Control
2010-05-24 08:53:27 -06:00
case BPMEM_FOGRANGE + 1 :
case BPMEM_FOGRANGE + 2 :
case BPMEM_FOGRANGE + 3 :
case BPMEM_FOGRANGE + 4 :
case BPMEM_FOGRANGE + 5 :
2011-01-28 21:31:56 -07:00
if ( ! GetConfig ( CONFIG_DISABLEFOG ) )
PixelShaderManager : : SetFogRangeAdjustChanged ( ) ;
break ;
2009-07-05 20:10:26 -06:00
case BPMEM_FOGPARAM0 :
case BPMEM_FOGBMAGNITUDE :
case BPMEM_FOGBEXPONENT :
case BPMEM_FOGPARAM3 :
if ( ! GetConfig ( CONFIG_DISABLEFOG ) )
PixelShaderManager : : SetFogParamChanged ( ) ;
break ;
case BPMEM_FOGCOLOR : // Fog Color
2009-12-09 06:51:28 -07:00
if ( ! GetConfig ( CONFIG_DISABLEFOG ) )
PixelShaderManager : : SetFogColorChanged ( ) ;
2009-07-05 20:10:26 -06:00
break ;
case BPMEM_ALPHACOMPARE : // Compare Alpha Values
2013-01-08 09:18:45 -07:00
PRIM_LOG ( " alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d " , bpmem . alpha_test . ref0 ,
bpmem . alpha_test . ref1 , bpmem . alpha_test . comp0 , bpmem . alpha_test . comp1 , bpmem . alpha_test . logic ) ;
PixelShaderManager : : SetAlpha ( bpmem . alpha_test ) ;
2009-07-05 20:10:26 -06:00
break ;
case BPMEM_BIAS : // BIAS
PRIM_LOG ( " ztex bias=0x%x " , bpmem . ztex1 . bias ) ;
2010-06-04 19:38:22 -06:00
PixelShaderManager : : SetZTextureBias ( bpmem . ztex1 . bias ) ;
2009-07-05 20:10:26 -06:00
break ;
case BPMEM_ZTEX2 : // Z Texture type
{
2010-06-04 19:38:22 -06:00
if ( bp . changes & 3 )
2009-07-05 20:10:26 -06:00
PixelShaderManager : : SetZTextureTypeChanged ( ) ;
# if defined(_DEBUG) || defined(DEBUGFAST)
const char * pzop [ ] = { " DISABLE " , " ADD " , " REPLACE " , " ? " } ;
const char * pztype [ ] = { " Z8 " , " Z16 " , " Z24 " , " ? " } ;
PRIM_LOG ( " ztex op=%s, type=%s " , pzop [ bpmem . ztex2 . op ] , pztype [ bpmem . ztex2 . type ] ) ;
# endif
break ;
}
// ----------------------------------
2009-07-26 03:52:35 -06:00
// Display Copy Filtering Control - GX_SetCopyFilter(u8 aa,u8 sample_pattern[12][2],u8 vf,u8 vfilter[7])
2009-07-05 20:10:26 -06:00
// Fields: Destination, Frame2Field, Gamma, Source
// ----------------------------------
2009-07-26 03:52:35 -06:00
case BPMEM_DISPLAYCOPYFILER : // if (aa) { use sample_pattern } else { use 666666 }
case BPMEM_DISPLAYCOPYFILER + 1 : // if (aa) { use sample_pattern } else { use 666666 }
case BPMEM_DISPLAYCOPYFILER + 2 : // if (aa) { use sample_pattern } else { use 666666 }
case BPMEM_DISPLAYCOPYFILER + 3 : // if (aa) { use sample_pattern } else { use 666666 }
case BPMEM_COPYFILTER0 : // if (vf) { use vfilter } else { use 595000 }
case BPMEM_COPYFILTER1 : // if (vf) { use vfilter } else { use 000015 }
2009-07-05 20:10:26 -06:00
break ;
2009-07-26 03:52:35 -06:00
// -----------------------------------
// Interlacing Control
// -----------------------------------
case BPMEM_FIELDMASK : // GX_SetFieldMask(u8 even_mask,u8 odd_mask)
case BPMEM_FIELDMODE : // GX_SetFieldMode(u8 field_mode,u8 half_aspect_ratio)
2009-07-05 20:10:26 -06:00
SetInterlacingMode ( bp ) ;
break ;
2009-07-26 03:52:35 -06:00
// ----------------------------------------
// Unimportant regs (Clock, Perf, ...)
// ----------------------------------------
case BPMEM_BUSCLOCK0 : // TB Bus Clock ?
case BPMEM_BUSCLOCK1 : // TB Bus Clock ?
case BPMEM_PERF0_TRI : // Perf: Triangles
case BPMEM_PERF0_QUAD : // Perf: Quads
case BPMEM_PERF1 : // Perf: Some Clock, Texels, TX, TC
2009-07-05 20:10:26 -06:00
break ;
// ----------------
// EFB Copy config
// ----------------
case BPMEM_EFB_TL : // EFB Source Rect. Top, Left
case BPMEM_EFB_BR : // EFB Source Rect. Bottom, Right (w, h - 1)
case BPMEM_EFB_ADDR : // EFB Target Address
break ;
// --------------
// Clear Config
// --------------
case BPMEM_CLEAR_AR : // Alpha and Red Components
case BPMEM_CLEAR_GB : // Green and Blue Components
case BPMEM_CLEAR_Z : // Z Components (24-bit Zbuffer)
break ;
// -------------------------
2009-07-26 03:52:35 -06:00
// Bounding Box Control
2009-07-05 20:10:26 -06:00
// -------------------------
case BPMEM_CLEARBBOX1 :
2010-07-06 07:14:51 -06:00
case BPMEM_CLEARBBOX2 :
{
2011-10-25 18:19:10 -06:00
if ( g_ActiveConfig . bUseBBox )
{
2011-10-28 14:12:12 -06:00
// Don't compute bounding box if this frame is being skipped!
// Wrong but valid values are better than bogus values...
if ( g_bSkipCurrentFrame )
break ;
2011-10-25 18:19:10 -06:00
if ( bp . address = = BPMEM_CLEARBBOX1 ) {
int right = bp . newvalue > > 10 ;
int left = bp . newvalue & 0x3ff ;
2009-07-05 20:10:26 -06:00
2011-10-25 18:19:10 -06:00
// We should only set these if bbox is calculated properly.
PixelEngine : : bbox [ 0 ] = left ;
PixelEngine : : bbox [ 1 ] = right ;
PixelEngine : : bbox_active = true ;
} else {
int bottom = bp . newvalue > > 10 ;
int top = bp . newvalue & 0x3ff ;
// We should only set these if bbox is calculated properly.
PixelEngine : : bbox [ 2 ] = top ;
PixelEngine : : bbox [ 3 ] = bottom ;
PixelEngine : : bbox_active = true ;
}
2009-07-05 20:10:26 -06:00
}
2010-07-06 07:14:51 -06:00
}
2009-07-05 20:10:26 -06:00
break ;
2012-08-07 10:57:53 -06:00
case BPMEM_TEXINVALIDATE :
// TODO: Needs some restructuring in TextureCacheBase.
2010-12-27 14:56:20 -07:00
break ;
2009-07-05 20:10:26 -06:00
case BPMEM_ZCOMPARE : // Set the Z-Compare and EFB pixel format
2011-04-03 12:08:04 -06:00
g_renderer - > SetColorMask ( ) ; // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel
2012-01-01 13:46:02 -07:00
OnPixelFormatChange ( ) ;
2010-12-27 14:56:20 -07:00
break ;
2009-07-05 20:10:26 -06:00
case BPMEM_MIPMAP_STRIDE : // MipMap Stride Channel
case BPMEM_COPYYSCALE : // Display Copy Y Scale
case BPMEM_IREF : /* 24 RID
21 BC3 - Ind . Tex Stage 3 NTexCoord
18 BI3 - Ind . Tex Stage 3 NTexMap
15 BC2 - Ind . Tex Stage 2 NTexCoord
12 BI2 - Ind . Tex Stage 2 NTexMap
9 BC1 - Ind . Tex Stage 1 NTexCoord
6 BI1 - Ind . Tex Stage 1 NTexMap
3 BC0 - Ind . Tex Stage 0 NTexCoord
2010-06-04 19:38:22 -06:00
0 BI0 - Ind . Tex Stage 0 NTexMap */
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_KSEL : // Texture Environment Swap Mode Table 0
case BPMEM_TEV_KSEL + 1 : // Texture Environment Swap Mode Table 1
case BPMEM_TEV_KSEL + 2 : // Texture Environment Swap Mode Table 2
case BPMEM_TEV_KSEL + 3 : // Texture Environment Swap Mode Table 3
case BPMEM_TEV_KSEL + 4 : // Texture Environment Swap Mode Table 4
case BPMEM_TEV_KSEL + 5 : // Texture Environment Swap Mode Table 5
case BPMEM_TEV_KSEL + 6 : // Texture Environment Swap Mode Table 6
case BPMEM_TEV_KSEL + 7 : // Texture Environment Swap Mode Table 7
case BPMEM_BP_MASK : // This Register can be used to limit to which bits of BP registers is actually written to. the mask is
2010-06-04 19:38:22 -06:00
// only valid for the next BP command, and will reset itself.
2009-07-05 20:10:26 -06:00
case BPMEM_IND_IMASK : // Index Mask ?
2009-07-26 03:52:35 -06:00
case BPMEM_REVBITS : // Always set to 0x0F when GX_InitRevBits() is called.
2009-07-05 20:10:26 -06:00
break ;
2012-03-25 04:35:57 -06:00
case BPMEM_UNKNOWN_57 : // Sunshine alternates this register between values 0x000 and 0xAAA
DEBUG_LOG ( VIDEO , " Unknown BP Reg 0x57: %08x " , bp . newvalue ) ;
2009-07-15 15:26:49 -06:00
break ;
2012-01-29 13:17:22 -07:00
case BPMEM_PRELOAD_ADDR :
case BPMEM_PRELOAD_TMEMEVEN :
case BPMEM_PRELOAD_TMEMODD : // Used when PRELOAD_MODE is set
2009-07-05 20:10:26 -06:00
break ;
2012-01-29 13:17:22 -07:00
case BPMEM_PRELOAD_MODE : // Set to 0 when GX_TexModeSync() is called.
2012-08-07 10:57:53 -06:00
// if this is different from 0, manual TMEM management is used (GX_PreloadEntireTexture).
2012-01-29 13:17:22 -07:00
if ( bp . newvalue ! = 0 )
{
2012-03-25 04:35:57 -06:00
// NOTE(neobrain): Apparently tmemodd doesn't affect hardware behavior at all (libogc uses it just as a buffer and switches its contents with tmemeven whenever this is called)
2012-01-29 13:17:22 -07:00
BPS_TmemConfig & tmem_cfg = bpmem . tmem_config ;
u8 * ram_ptr = Memory : : GetPointer ( tmem_cfg . preload_addr < < 5 ) ;
2012-03-25 04:35:57 -06:00
u32 tmem_addr = tmem_cfg . preload_tmem_even * TMEM_LINE_SIZE ;
u32 size = tmem_cfg . preload_tile_info . count * 32 ;
2012-03-23 05:10:48 -06:00
2012-03-25 04:35:57 -06:00
// Check if the game has overflowed TMEM, and copy up to the limit.
// Paper Mario does this when entering the Great Boogly Tree (Chap 2)
if ( ( tmem_addr + size ) > TMEM_SIZE )
size = TMEM_SIZE - tmem_addr ;
2012-03-23 05:10:48 -06:00
2012-01-29 13:17:22 -07:00
memcpy ( texMem + tmem_addr , ram_ptr , size ) ;
}
2009-07-26 03:52:35 -06:00
break ;
2009-07-05 20:10:26 -06:00
// ------------------------------------------------
// On Default, we try to look for other things
// before we give up and say its an unknown opcode
// ------------------------------------------------
default :
switch ( bp . address & 0xFC ) // Texture sampler filter
{
// -------------------------
// Texture Environment Order
// -------------------------
case BPMEM_TREF :
case BPMEM_TREF + 4 :
break ;
// ----------------------
// Set wrap size
2010-06-04 19:38:22 -06:00
// ----------------------
2009-07-05 20:10:26 -06:00
case BPMEM_SU_SSIZE :
case BPMEM_SU_TSIZE :
case BPMEM_SU_SSIZE + 2 :
case BPMEM_SU_TSIZE + 2 :
case BPMEM_SU_SSIZE + 4 :
case BPMEM_SU_TSIZE + 4 :
case BPMEM_SU_SSIZE + 6 :
case BPMEM_SU_TSIZE + 6 :
case BPMEM_SU_SSIZE + 8 :
case BPMEM_SU_TSIZE + 8 :
case BPMEM_SU_SSIZE + 10 :
case BPMEM_SU_TSIZE + 10 :
case BPMEM_SU_SSIZE + 12 :
case BPMEM_SU_TSIZE + 12 :
case BPMEM_SU_SSIZE + 14 :
case BPMEM_SU_TSIZE + 14 :
2010-06-04 19:38:22 -06:00
PixelShaderManager : : SetTexCoordChanged ( ( bp . address - BPMEM_SU_SSIZE ) > > 1 ) ;
2009-07-05 20:10:26 -06:00
break ;
// ------------------------
// BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S
// BPMEM_TX_SETMODE1 - (LOD Stuff) - Max LOD, Min LOD
2010-06-04 19:38:22 -06:00
// ------------------------
2009-07-05 20:10:26 -06:00
case BPMEM_TX_SETMODE0 : // (0x90 for linear)
case BPMEM_TX_SETMODE0_4 :
2010-01-12 16:40:30 -07:00
// Shouldn't need to call this here, we call it for each active texture right before rendering
SetTextureMode ( bp ) ;
break ;
case BPMEM_TX_SETMODE1 :
2009-07-05 20:10:26 -06:00
case BPMEM_TX_SETMODE1_4 :
break ;
// --------------------------------------------
// BPMEM_TX_SETIMAGE0 - Texture width, height, format
// BPMEM_TX_SETIMAGE1 - even LOD address in TMEM - Image Type, Cache Height, Cache Width, TMEM Offset
// BPMEM_TX_SETIMAGE2 - odd LOD address in TMEM - Cache Height, Cache Width, TMEM Offset
// BPMEM_TX_SETIMAGE3 - Address of Texture in main memory
2010-06-04 19:38:22 -06:00
// --------------------------------------------
2009-07-05 20:10:26 -06:00
case BPMEM_TX_SETIMAGE0 :
case BPMEM_TX_SETIMAGE0_4 :
case BPMEM_TX_SETIMAGE1 :
case BPMEM_TX_SETIMAGE1_4 :
case BPMEM_TX_SETIMAGE2 :
case BPMEM_TX_SETIMAGE2_4 :
case BPMEM_TX_SETIMAGE3 :
case BPMEM_TX_SETIMAGE3_4 :
break ;
// -------------------------------
// Set a TLUT
// BPMEM_TX_SETTLUT - Format, TMEM Offset (offset of TLUT from start of TMEM high bank > > 5)
2010-06-04 19:38:22 -06:00
// -------------------------------
2009-07-05 20:10:26 -06:00
case BPMEM_TX_SETTLUT :
case BPMEM_TX_SETLUT_4 :
break ;
2010-01-12 16:40:30 -07:00
2009-07-05 20:10:26 -06:00
// ---------------------------------------------------
// Set the TEV Color
2010-06-04 19:38:22 -06:00
// ---------------------------------------------------
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_REGISTER_L : // Reg 1
case BPMEM_TEV_REGISTER_H :
case BPMEM_TEV_REGISTER_L + 2 : // Reg 2
case BPMEM_TEV_REGISTER_H + 2 :
case BPMEM_TEV_REGISTER_L + 4 : // Reg 3
case BPMEM_TEV_REGISTER_H + 4 :
case BPMEM_TEV_REGISTER_L + 6 : // Reg 4
case BPMEM_TEV_REGISTER_H + 6 :
2011-07-04 07:49:40 -06:00
// some games only send the _L part, so always update
// there actually are 2 register behind each of these
// addresses, selected by the type bit.
2009-07-05 20:10:26 -06:00
{
2010-01-12 16:40:30 -07:00
// don't compare with changes!
int num = ( bp . address > > 1 ) & 0x3 ;
2011-07-04 07:49:40 -06:00
if ( ( bp . address & 1 ) = = 0 )
PixelShaderManager : : SetColorChanged ( bpmem . tevregs [ num ] . low . type , num , false ) ;
else
PixelShaderManager : : SetColorChanged ( bpmem . tevregs [ num ] . high . type , num , true ) ;
2009-07-05 20:10:26 -06:00
}
2010-01-12 16:40:30 -07:00
break ;
2009-07-05 20:10:26 -06:00
// ------------------------------------------------
// On Default, we try to look for other things
// before we give up and say its an unknown opcode
// again ...
// ------------------------------------------------
default :
switch ( bp . address & 0xF0 )
{
// --------------
// Indirect Tev
// --------------
case BPMEM_IND_CMD :
case BPMEM_IND_CMD + 1 :
case BPMEM_IND_CMD + 2 :
case BPMEM_IND_CMD + 3 :
case BPMEM_IND_CMD + 4 :
case BPMEM_IND_CMD + 5 :
case BPMEM_IND_CMD + 6 :
case BPMEM_IND_CMD + 7 :
case BPMEM_IND_CMD + 8 :
case BPMEM_IND_CMD + 9 :
case BPMEM_IND_CMD + 10 :
case BPMEM_IND_CMD + 11 :
case BPMEM_IND_CMD + 12 :
case BPMEM_IND_CMD + 13 :
case BPMEM_IND_CMD + 14 :
case BPMEM_IND_CMD + 15 :
break ;
// --------------------------------------------------
// Set Color/Alpha of a Tev
// BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D
// BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap
// --------------------------------------------------
case BPMEM_TEV_COLOR_ENV : // Texture Environment 1
case BPMEM_TEV_ALPHA_ENV :
case BPMEM_TEV_COLOR_ENV + 2 : // Texture Environment 2
case BPMEM_TEV_ALPHA_ENV + 2 :
case BPMEM_TEV_COLOR_ENV + 4 : // Texture Environment 3
case BPMEM_TEV_ALPHA_ENV + 4 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 6 : // Texture Environment 4
case BPMEM_TEV_ALPHA_ENV + 6 :
case BPMEM_TEV_COLOR_ENV + 8 : // Texture Environment 5
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 8 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 10 : // Texture Environment 6
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 10 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 12 : // Texture Environment 7
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 12 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 14 : // Texture Environment 8
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 14 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 16 : // Texture Environment 9
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 16 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 18 : // Texture Environment 10
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 18 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 20 : // Texture Environment 11
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 20 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 22 : // Texture Environment 12
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 22 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 24 : // Texture Environment 13
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 24 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 26 : // Texture Environment 14
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 26 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 28 : // Texture Environment 15
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 28 :
2010-05-24 08:53:27 -06:00
case BPMEM_TEV_COLOR_ENV + 30 : // Texture Environment 16
2009-07-05 20:10:26 -06:00
case BPMEM_TEV_ALPHA_ENV + 30 :
break ;
default :
2009-07-15 15:26:49 -06:00
WARN_LOG ( VIDEO , " Unknown BP opcode: address = 0x%08x value = 0x%08x " , bp . address , bp . newvalue ) ;
2009-07-05 20:10:26 -06:00
break ;
2010-07-06 07:14:51 -06:00
}
2009-07-05 20:10:26 -06:00
}
2009-07-22 16:50:52 -06:00
}
2009-07-05 20:10:26 -06:00
}
2012-01-01 13:46:02 -07:00
// Called when loading a saved state.
void BPReload ( )
{
2012-12-23 05:32:23 -07:00
// restore anything that goes straight to the renderer.
// let's not risk actually replaying any writes.
// note that PixelShaderManager is already covered since it has its own DoState.
SetGenerationMode ( ) ;
SetScissor ( ) ;
SetLineWidth ( ) ;
SetDepthMode ( ) ;
SetLogicOpMode ( ) ;
SetDitherMode ( ) ;
SetBlendMode ( ) ;
SetColorMask ( ) ;
OnPixelFormatChange ( ) ;
{
BPCmd bp = { BPMEM_TX_SETMODE0 , 0xFFFFFF , static_cast < int > ( ( ( u32 * ) & bpmem ) [ BPMEM_TX_SETMODE0 ] ) } ;
SetTextureMode ( bp ) ;
}
{
BPCmd bp = { BPMEM_TX_SETMODE0_4 , 0xFFFFFF , static_cast < int > ( ( ( u32 * ) & bpmem ) [ BPMEM_TX_SETMODE0_4 ] ) } ;
SetTextureMode ( bp ) ;
}
{
BPCmd bp = { BPMEM_FIELDMASK , 0xFFFFFF , static_cast < int > ( ( ( u32 * ) & bpmem ) [ BPMEM_FIELDMASK ] ) } ;
SetInterlacingMode ( bp ) ;
}
{
BPCmd bp = { BPMEM_FIELDMODE , 0xFFFFFF , static_cast < int > ( ( ( u32 * ) & bpmem ) [ BPMEM_FIELDMODE ] ) } ;
SetInterlacingMode ( bp ) ;
2012-01-01 13:46:02 -07:00
}
}