Path: blob/master/libmupen64plus/mupen64plus-video-rice/src/OGLCombinerNV.cpp
2 views
/*1Copyright (C) 2003 Rice196423This program is free software; you can redistribute it and/or4modify it under the terms of the GNU General Public License5as published by the Free Software Foundation; either version 26of the License, or (at your option) any later version.78This program is distributed in the hope that it will be useful,9but WITHOUT ANY WARRANTY; without even the implied warranty of10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11GNU General Public License for more details.1213You should have received a copy of the GNU General Public License14along with this program; if not, write to the Free Software15Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.16*/1718#include "OGLExtensions.h"1920#include "OGLCombinerNV.h"21#include "OGLRender.h"22#include "OGLGraphicsContext.h"2324//========================================================================25#define MUX_E_F (MUX_PRIMLODFRAC+1)26#define MUX_SPARE1 (MUX_E_F+1)27#define MUX_SECONDARY_COLOR (MUX_SPARE1+1)28#define MUX_NOT_USED MUX_ERR29#define MUX_COMBINED_SIGNED (MUX_SECONDARY_COLOR+1) //Use only by Nvidia register combiner303132typedef struct {33GLenum input;34GLenum mapping;35GLenum componentUsage;36}RGBMapType;3738RGBMapType RGBmap1[] =39{40{GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_0 = 0,41{GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB}, //MUX_1, = ZERO NEG42{GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_COMBINED,43{GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_TEXEL0,44{GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_TEXEL1,45{GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_PRIM,46{GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_SHADE,47{GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_ENV,48{GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_COMBALPHA,49{GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_T0_ALPHA,50{GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_T1_ALPHA,51{GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_PRIM_ALPHA,52{GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_SHADE_ALPHA,53{GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_ENV_ALPHA,54{GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_LODFRAC,55{GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_PRIMLODFRAC,56{GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_E_F,57{GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_SPARE1,58{GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_SECONDARY_COLOR,59{GL_SPARE0_NV, GL_SIGNED_IDENTITY_NV, GL_RGB}, //MUX_COMBINED_SIGNED,60};616263//========================================================================64COGLColorCombinerNvidia::COGLColorCombinerNvidia(CRender *pRender) :65COGLColorCombiner4(pRender)66{67m_bNVSupported = false;68delete m_pDecodedMux;69m_pDecodedMux = new COGLDecodedMux;70m_pDecodedMux->m_maxConstants=2;71}7273COGLColorCombinerNvidia::~COGLColorCombinerNvidia()74{75m_vCompiledSettings.clear();76}777879bool COGLColorCombinerNvidia::Initialize(void)80{81m_bNVSupported = false;8283if( COGLColorCombiner4::Initialize() )84{85m_bSupportMultiTexture = true;8687COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);88if( pcontext->IsExtensionSupported("GL_NV_texture_env_combine4") || pcontext->IsExtensionSupported("GL_NV_register_combiners") )89{90m_bNVSupported = true;91glEnable(GL_REGISTER_COMBINERS_NV);92return true;93}94else95{96DebugMessage(M64MSG_ERROR, "Your video card does not support Nvidia OpenGL extension combiner");97glDisable(GL_REGISTER_COMBINERS_NV);98return false;99}100}101102glDisable(GL_REGISTER_COMBINERS_NV);103return false;104}105106void COGLColorCombinerNvidia::InitCombinerCycle12(void)107{108if( !m_bNVSupported ) {COGLColorCombiner4::InitCombinerCycle12(); return;}109110glEnable(GL_REGISTER_COMBINERS_NV);111112#ifdef DEBUGGER113if( debuggerDropCombiners )114{115m_vCompiledSettings.clear();116m_dwLastMux0 = m_dwLastMux1 = 0;117debuggerDropCombiners = false;118}119#endif120121m_pOGLRender->EnableMultiTexture();122bool combinerIsChanged = false;123124if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 )125{126combinerIsChanged = true;127m_lastIndex = FindCompiledMux();128if( m_lastIndex < 0 ) // Can not found129{130NVRegisterCombinerParserType result;131ParseDecodedMux(result);132m_lastIndex= SaveParserResult(result);133}134135m_dwLastMux0 = m_pDecodedMux->m_dwMux0;136m_dwLastMux1 = m_pDecodedMux->m_dwMux1;137GenerateNVRegisterCombinerSetting(m_lastIndex);138}139140m_pOGLRender->SetAllTexelRepeatFlag();141142if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded )143{144gRDP.texturesAreReloaded = false;145if( m_bCycleChanged || combinerIsChanged )146{147GenerateNVRegisterCombinerSettingConstants(m_lastIndex);148GenerateNVRegisterCombinerSetting(m_lastIndex);149ApplyFogAtFinalStage();150}151else if( gRDP.colorsAreReloaded )152{153GenerateNVRegisterCombinerSettingConstants(m_lastIndex);154}155156gRDP.colorsAreReloaded = false;157}158}159160void COGLColorCombinerNvidia::ParseDecodedMux(NVRegisterCombinerParserType &result) // Compile the decodedMux into NV register combiner setting161{162//int stagesForRGB=0;163//int stagesForAlpha=0;164//int stages=0;165166COGLDecodedMux &mux = *(COGLDecodedMux*)m_pDecodedMux;167mux.To_AB_Add_CD_Format();168169result.stagesUsed=0;170171if( StagesNeedToUse(mux, N64Cycle0RGB) == 0 )172{173// Nothing to be done for RGB174ByPassGeneralStage(result.s1rgb);175ByPassGeneralStage(result.s2rgb);176ByPassFinalStage(result.finalrgb);177}178else if( StagesNeedToUse(mux, N64Cycle0RGB) == 1 )179{180result.stagesUsed = 1;181Parse1Mux(mux, N64Cycle0RGB, result.s1rgb);182if( StagesNeedToUse(mux, N64Cycle1RGB) == 0 )183{184ByPassGeneralStage(result.s2rgb);185ByPassFinalStage(result.finalrgb);186}187else188{189result.stagesUsed = 2;190Parse1MuxForStage2AndFinalStage(mux, N64Cycle1RGB, result.s2rgb, result.finalrgb);191}192}193else194{195result.stagesUsed = 2;196Parse1Mux2Stages(mux, N64Cycle0RGB, result.s1rgb, result.s2rgb);197Parse1MuxForFinalStage(mux, N64Cycle1RGB, result.finalrgb);198}199200// Debug texel1201/*202if( m_pDecodedMux->m_bTexel0IsUsed && m_pDecodedMux->m_bTexel1IsUsed )203{204result.finalrgb.a = MUX_TEXEL0;205result.finalrgb.b = MUX_TEXEL1;206result.finalrgb.c = MUX_0;207result.finalrgb.d = MUX_0;208}209*/210211if( StagesNeedToUse(mux, N64Cycle0Alpha) == 0 )212{213// Nothing to be done for Alpha214ByPassGeneralStage(result.s1alpha);215ByPassGeneralStage(result.s2alpha);216ByPassFinalStage(result.finalalpha);217}218else if( Parse1Mux2Stages(mux, N64Cycle0Alpha, result.s1alpha, result.s2alpha) == 1 )219{220// Only 1 NV stage is used221if( result.stagesUsed == 0 ) result.stagesUsed = 1;222if( StagesNeedToUse(mux, N64Cycle1Alpha) == 0 )223{224ByPassGeneralStage(result.s2alpha);225}226else227{228Parse1Mux(mux, N64Cycle1Alpha, result.s2alpha);229result.stagesUsed = 2;230}231}232else233{234// The 1st is used 2 stages, skip the 2nd N64 alpha setting235result.stagesUsed = 2;236result.s2alpha.a=MUX_COMBINED;237result.s2alpha.b=MUX_1;238result.s2alpha.c=m_pDecodedMux->m_n64Combiners[N64Cycle0Alpha].d;239result.s2alpha.d=MUX_1;240}241242// Parse Alpha setting, alpha does not have a final stage243ByPassFinalStage(result.finalalpha);244ParseDecodedMuxForConstant(result);245}246247void COGLColorCombinerNvidia::ParseDecodedMuxForConstant(NVRegisterCombinerParserType &result)248{249result.constant0 = MUX_0;250result.constant1 = MUX_0;251bool const0Used=false;252bool const1Used=false;253if( m_pDecodedMux->isUsed(MUX_PRIM) )254{255result.constant0 = MUX_PRIM;256const0Used = true;257}258if( m_pDecodedMux->isUsed(MUX_ENV) )259{260if( const0Used )261{262result.constant1 = MUX_ENV;263const1Used = true;264}265else266{267result.constant0 = MUX_ENV;268const0Used = true;269}270}271if( m_pDecodedMux->isUsed(MUX_LODFRAC) && !const1Used )272{273if( !const1Used )274{275result.constant1 = MUX_LODFRAC;276const1Used = true;277}278else if( !const0Used )279{280result.constant0 = MUX_LODFRAC;281const0Used = true;282}283}284285if( m_pDecodedMux->isUsed(MUX_PRIMLODFRAC) && !const1Used )286{287if( !const1Used )288{289result.constant1 = MUX_PRIMLODFRAC;290const1Used = true;291}292else if( !const0Used )293{294result.constant0 = MUX_PRIMLODFRAC;295const0Used = true;296}297}298}299300int COGLColorCombinerNvidia::StagesNeedToUse(COGLDecodedMux &mux, N64StageNumberType stage)301{302N64CombinerType &m = mux.m_n64Combiners[stage];303304switch(mux.splitType[stage])305{306case CM_FMT_TYPE_NOT_USED:307return 0;308case CM_FMT_TYPE_D: // = A ==> can be done in 1 NV stage309case CM_FMT_TYPE_A_ADD_D: // = A+D ==> can be done in 1 NV stage310case CM_FMT_TYPE_A_MOD_C: // = A*C ==> can be done in 1 NV stage311case CM_FMT_TYPE_A_SUB_B: // = A-B ==> can be done in 1 NV stage312case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D ==> can be done in 1 NV stage313case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B ==> can be done in 1 NV stage314case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C ==> can be done in 1 NV stage315case CM_FMT_TYPE_AB_ADD_CD: // = AB+CD316case CM_FMT_TYPE_AB_SUB_CD: // = AB-CD317return 1;318case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage319if( m.a == m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner320return 1;321else // Need two NV stages for this N64 combiner322return 2;323case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage324default:325//if( m.a == m.d ) // = (A-B)*C+A = A(C+1)-B*C = A-B*C326// return 1;327//else328if( m.d == m.c ) // = (A-B)*C+C = A*C+(1-B)*C329return 1;330else // = (A-B)*C+D, need two NV stages331return 2;332}333}334335bool isTex(uint8 val)336{337if( (val&MUX_MASK) == MUX_TEXEL0 || (val&MUX_MASK) == MUX_TEXEL1 )338return true;339else340return false;341}342int COGLColorCombinerNvidia::Parse1Mux(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res) // Compile the decodedMux into NV register combiner setting343{344// Parse 1 N64 combiner, generate result and return how many NV stage is needed.345// result will be put into only 1 NV stage, not the 2nd one even if 2nd one is needed.346// The caller of this function will handle the 2nd NV stage if it is needed347348349// Up to here, the m_pDecodedMux is already simplied, N64 stage 1 and stage 2 have been350// adjusted so stage1 is almost always complicated than stage 2351352// The stage type in decodedMux is still in (A-B)*C+D format353// we need to parser and translate it to A*B+C*D format for NV register general combiner354// and to A*D+(1-A)*C+D format for the NV final combiner355356// Remember that N64 has two stages, NV has two general combiner stages and 1 final combiner stage357// NV should be able to simulate exactly all possible N64 combiner settings358/*359CM_FMT_TYPE1_D, // = A ==> can be done in 1 NV stage360CM_FMT_TYPE2_A_ADD_D, // = A+D ==> can be done in 1 NV stage361CM_FMT_TYPE3_A_MOD_C, // = A*C ==> can be done in 1 NV stage362CM_FMT_TYPE4_A_SUB_B, // = A-B ==> can be done in 1 NV stage363CM_FMT_TYPE5_A_MOD_C_ADD_D, // = A*C+D ==> can be done in 1 NV stage364CM_FMT_TYPE6_A_LERP_B_C, // = (A-B)*C+B ==> can be done in 1 NV stage365CM_FMT_TYPE8_A_SUB_B_MOD_C, // = (A-B)*C ==> can be done in 1 NV stage366367CM_FMT_TYPE7_A_SUB_B_ADD_D, // = A-B+C ==> can not be done in 1 stage368CM_FMT_TYPE9_A_B_C_D, // = (A-B)*C+D ==> can not be done in 1 stage369370the last two ones, since we can neither do it in the final stage, if the 1st N64 stage371happen to be one of the two types and have used the two NV general combiners, and if the 2nd N64372combiner happens to be one of the two types as well, then we have to simplify the N64 combiner so373to implement it. In such as case, the N64 combiners are too complicated, we just do what either as374we can to implement it.375376Use UNSIGNED_INVERT of ZERO ==> ONE377378// If the 1st N64 stage can not be done in 1 NV stage, then we will do 1st N64 stage379// by using 2 NV general combiner stages, and the 2nd N64 stage by using the NV final380// combiner stage.381382// RGB channel and alpha channel is the same in the general combiner, but different in383// the final combiner. In fact, final combiner does not do anything for alpha channel384// so alpha channel setting of both N64 combiner must be implemented by the two NV general385// combiner386387If we can not implement the two alpha setting in 2 NV combiner stages, we will do what either388as we can.389390*/391N64CombinerType &m = mux.m_n64Combiners[stage];392393switch(mux.splitType[stage])394{395case CM_FMT_TYPE_NOT_USED:396res.a=MUX_0;397res.b=MUX_0;398res.c=MUX_0;399res.d=MUX_0;400return 0;401break;402case CM_FMT_TYPE_D: // = A ==> can be done in 1 NV stage403res.a=m.d;404res.b=MUX_1;405res.c=MUX_0;406res.d=MUX_0;407return 1;408break;409case CM_FMT_TYPE_A_ADD_D: // = A+D ==> can be done in 1 NV stage410res.a=m.a;411res.b=MUX_1;412res.c=m.d;413res.d=MUX_1;414return 1;415break;416case CM_FMT_TYPE_A_MOD_C: // = A*C ==> can be done in 1 NV stage417res.a=m.a;418res.b=m.c;419res.c=MUX_0;420res.d=MUX_0;421return 1;422break;423case CM_FMT_TYPE_A_SUB_B: // = A-B ==> can be done in 1 NV stage424res.a=m.a;425res.b=MUX_1;426res.c=m.b|MUX_NEG;427res.d=MUX_1;428return 1;429break;430case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D ==> can be done in 1 NV stage431res.a=m.a;432res.b=m.c;433res.c=m.d;434res.d=MUX_1;435return 1;436break;437case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B ==> can be done in 1 NV stage438// = AC+(1-C)B439res.a=m.a;440res.b=m.c;441res.c=m.c^MUX_COMPLEMENT;442res.d=m.b;443return 1;444break;445case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C ==> can be done in 1 NV stage446res.a=m.a;447res.b=m.c;448res.c=m.b|MUX_NEG;449res.d=m.c;450return 1;451break;452case CM_FMT_TYPE_AB_ADD_CD: // = AB+CD453res.a = m.a;454res.b = m.b;455res.c = m.c;456res.d = m.d;457return 1;458break;459case CM_FMT_TYPE_AB_SUB_CD: // = AB-CD460res.a = m.a;461res.b = m.b;462res.c = m.c|MUX_NEG;463res.d = m.d;464return 1;465break;466case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage467if( m.a == m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner468{469res.a=m.a;470res.b=MUX_1;471res.c=m.b|MUX_NEG;472res.d=MUX_1;473return 1;474}475else // Need two NV stages for this N64 combiner476{477// Stage 1: R1=A-B478res.a=m.a;479res.b=MUX_1;480481if( isTex(res.b) || !isTex(res.d) )482{483res.c=m.b|MUX_NEG;484res.d=MUX_1;485}486else487{488res.c=m.d;489res.d=MUX_1;490}491return 2;492}493break;494case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage495default:496if( m.a == m.d ) // = (A-B)*C+A = A(C+1)-B*C = A-B*C497{498res.a=m.a;499res.b=m.c;500res.c=m.b|MUX_NEG;501res.d=m.c;502return 1;503}504else if( m.d == m.c ) // = (A-B)*C+C = A*C+(1-B)*C505{506res.a=m.a;507res.b=m.c;508res.c=m.b^MUX_COMPLEMENT;509res.d=m.c;510return 1;511}512else // = (A-B)*C+D, need two NV stages513{514// Stage 1: R1=(A-B)*C = AC-BC515if( isTex(m.d) )516{517// = A*C+D518res.a=m.a;519res.b=m.c;520res.c=m.d;521res.d=MUX_1;522}523else524{525// = (A-B)*C = A*C - B*C526res.a=m.a;527res.b=m.c;528res.c=m.b|MUX_NEG;529res.d=m.c;530}531return 2;532}533break;534}535}536537int COGLColorCombinerNvidia::Parse1Mux2Stages(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res, NVGeneralCombinerType &res2)538{539N64CombinerType &m = mux.m_n64Combiners[stage];540switch(mux.splitType[stage])541{542case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage543if( m.a != m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner544{545// Stage 1: R1=A-B546res.a=m.a;547res.b=MUX_1;548res.c=m.b|MUX_NEG;549res.d=MUX_1;550551res2.a=MUX_COMBINED_SIGNED;552res2.b=MUX_1;553res2.c=m.d;554res2.d=MUX_1;555556return 2;557}558break;559case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage560case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+D ==> can not be done in 1 stage561//if( m.a != m.d && m.d != m.c )562{563// Stage 1: R1=(A-B)*C = AC-BC564res.a=m.a;565res.b=m.c;566res.c=m.b|MUX_NEG;567res.d=m.c;568569res2.a=MUX_COMBINED_SIGNED;570res2.b=MUX_1;571res2.c=m.d;572res2.d=MUX_1;573574return 2;575}576break;577default:578break;579}580return Parse1Mux(mux, stage, res);581}582583584void COGLColorCombinerNvidia::Parse1MuxForFinalStage(COGLDecodedMux &mux, N64StageNumberType stage, NVFinalCombinerType &res)585{586N64CombinerType &m = mux.m_n64Combiners[stage];587588// Final stage equation is: AB+(1-A)C+D589switch(mux.splitType[stage])590{591case CM_FMT_TYPE_NOT_USED:592res.a=MUX_0;593res.b=MUX_0;594res.c=MUX_0;595res.d=MUX_0;596break;597case CM_FMT_TYPE_D: // = A ==> can be done in 1 NV stage598res.a=m.a;599res.b=MUX_1;600res.c=MUX_0;601res.d=MUX_0;602break;603case CM_FMT_TYPE_A_ADD_D: // = A+D ==> can be done in 1 NV stage604res.a=m.a;605res.b=MUX_1;606res.c=MUX_0;607res.d=m.d;608break;609case CM_FMT_TYPE_A_MOD_C: // = A*C ==> can be done in 1 NV stage610res.a=m.a;611res.b=m.c;612res.c=MUX_0;613res.d=MUX_0;614break;615case CM_FMT_TYPE_A_SUB_B: // = A-B ==> can be done in 1 NV stage616res.a=m.a;617res.b=MUX_1;618res.c=MUX_0;619res.d=m.b|MUX_NEG;620break;621case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D ==> can be done in 1 NV stage622res.a=m.a;623res.b=m.c;624res.c=MUX_0;625res.d=m.d;626break;627case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B ==> can be done in 1 NV stage628// = AC+(1-B)C629res.a = m.c;630res.b = MUX_0;631res.c = m.b;632res.d = MUX_E_F;633res.e = m.a;634res.f = m.c;635break;636case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C ==> can be done in 1 NV stage637res.a=m.c;638res.b=m.a;639res.c=m.b;640res.d=m.b|MUX_NEG;641break;642case CM_FMT_TYPE_AB_ADD_CD: // = AB+CD643res.a = m.a;644res.b = m.b;645res.e = m.c;646res.f = m.d;647res.c = MUX_0;648res.d = MUX_E_F;649break;650case CM_FMT_TYPE_AB_SUB_CD: // = AB-CD651res.a = m.a;652res.b = m.b;653res.e = m.c|MUX_NEG;654res.f = m.d;655res.c = MUX_0;656res.d = MUX_E_F;657break;658case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage659if( m.a == m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner660{661res.a=m.a;662res.b=MUX_1;663res.c=MUX_0;664res.d=m.b|MUX_NEG;665}666else // Need two NV stages for this N64 combiner667{668TRACE0("NV Combiner parse, check me, not fully support this combiner");669// final combiner can not fully support this combiner setting670// Stage 1: R1=A-B671res.a=m.a;672res.b=MUX_1;673res.c=MUX_0;674res.d=m.b|MUX_NEG;675}676break;677case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage678default:679if( m.a == m.d ) // = (A-B)*C+A = A(C+1)-B*C = A-B*C680{681/*682res.a=m.c;683res.b=m.b|MUX_NEG;684res.c=MUX_0;685res.d=m.a;686*/687res.a=m.c;688res.b=m.a;689res.c=m.b;690res.d=MUX_0;691}692else if( m.d == m.c ) // = (A-B)*C+C = A*C+(1-B)*C693{694res.a=m.b;695res.b=MUX_0;696res.c=m.c;697res.d=MUX_E_F;698res.e=m.a;699res.f=m.c;700}701else // = (A-B)*C+D, need two NV stages702{703TRACE0("NV Combiner parse, check me, not fully support this combiner");704// final combiner can not fully support this combiner setting705// Stage 1: R1=(A-B)*C = AC-BC706res.a=m.c;707res.b=m.a;708res.c=m.b;709res.d=m.b|MUX_NEG;710}711break;712}713res.g=MUX_COMBINED;714}715716int COGLColorCombinerNvidia::Parse1MuxForStage2AndFinalStage(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res, NVFinalCombinerType &fres)717{718if( Parse1Mux(mux, stage, res) == 1 )719{720ByPassFinalStage(fres);721return 1;722}723else724{725ByPassFinalStage(fres);726fres.a=MUX_COMBINED;727fres.b=MUX_1;728fres.d = mux.m_n64Combiners[stage].d;729fres.g=MUX_COMBINED;730return 2;731}732}733734void COGLColorCombinerNvidia::ByPassFinalStage(NVFinalCombinerType &fres)735{736fres.a=MUX_0;737fres.b=MUX_0;738fres.c=MUX_0;739fres.d=MUX_COMBINED;740fres.e=MUX_0;741fres.f=MUX_0;742fres.g=MUX_COMBINED;743}744745void COGLColorCombinerNvidia::ByPassGeneralStage(NVGeneralCombinerType &res)746{747res.a=MUX_1;748res.b=MUX_COMBINED;749res.c=MUX_0;750res.d=MUX_0;751}752753int COGLColorCombinerNvidia::FindCompiledMux(void)754{755for( uint32 i=0; i<m_vCompiledSettings.size(); i++ )756{757if( m_vCompiledSettings[i].dwMux0 == m_pDecodedMux->m_dwMux0 && m_vCompiledSettings[i].dwMux1 == m_pDecodedMux->m_dwMux1 )758return i;759}760761return -1;762}763void COGLColorCombinerNvidia::GenerateNVRegisterCombinerSettingConstants(int index)764{765NVRegisterCombinerSettingType &info = m_vCompiledSettings[index];766uint8 consts[2] = {info.constant0,info.constant1};767768float *pf;769770for( int i=0; i<2; i++ )771{772switch( consts[i] )773{774case MUX_PRIM:775pf = GetPrimitiveColorfv();776pglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV+i,pf);777break;778case MUX_ENV:779pf = GetEnvColorfv();780pglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV+i,pf);781break;782case MUX_LODFRAC:783case MUX_PRIMLODFRAC:784{785float frac = gRDP.primLODFrac / 255.0f;786float tempf[4] = {frac,frac,frac,frac};787pglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV+i,tempf);788break;789}790}791}792}793794void COGLColorCombinerNvidia::GenerateNVRegisterCombinerSetting(int index)795{796if( index < 0 || index >= (int)m_vCompiledSettings.size() )797{798TRACE0("NV Register combiner, vector index out of range");799return;800}801802NVRegisterCombinerSettingType &info = m_vCompiledSettings[index];803804pglCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV,info.numOfStages);805806uint32 i;807808if( info.numOfStages > 0 )809{810for( i=0; i<4; i++ )811{812pglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, info.stage1RGB[i].variable, info.stage1RGB[i].input,813info.stage1RGB[i].mapping, info.stage1RGB[i].componentUsage );814}815816for( i=0; i<4; i++ )817{818pglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, info.stage1Alpha[i].variable, info.stage1Alpha[i].input,819info.stage1Alpha[i].mapping, info.stage1Alpha[i].componentUsage );820}821822pglCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, info.stage1outputRGB.abOutput, info.stage1outputRGB.cdOutput,823info.stage1outputRGB.sumOutput, info.stage1outputRGB.scale, info.stage1outputRGB.bias, info.stage1outputRGB.abDotProduct,824info.stage1outputRGB.cdDotProduct, info.stage1outputRGB.muxSum);825826pglCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, info.stage2outputAlpha.abOutput, info.stage2outputAlpha.cdOutput,827info.stage2outputAlpha.sumOutput, info.stage2outputAlpha.scale, info.stage2outputAlpha.bias, info.stage2outputAlpha.abDotProduct,828info.stage2outputAlpha.cdDotProduct, info.stage2outputAlpha.muxSum);829830if( info.numOfStages > 1 )831{832for( i=0; i<4; i++ )833{834pglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, info.stage2RGB[i].variable,835info.stage2RGB[i].input, info.stage2RGB[i].mapping, info.stage2RGB[i].componentUsage );836}837838for( i=0; i<4; i++ )839{840pglCombinerInputNV(GL_COMBINER1_NV, GL_ALPHA, info.stage2Alpha[i].variable, info.stage2Alpha[i].input,841info.stage2Alpha[i].mapping, info.stage2Alpha[i].componentUsage );842}843844pglCombinerOutputNV(GL_COMBINER1_NV, GL_RGB, info.stage2outputRGB.abOutput, info.stage2outputRGB.cdOutput,845info.stage2outputRGB.sumOutput, info.stage2outputRGB.scale, info.stage2outputRGB.bias, info.stage2outputRGB.abDotProduct,846info.stage2outputRGB.cdDotProduct, info.stage2outputRGB.muxSum);847848pglCombinerOutputNV(GL_COMBINER1_NV, GL_ALPHA, info.stage2outputAlpha.abOutput, info.stage2outputAlpha.cdOutput,849info.stage2outputAlpha.sumOutput, info.stage2outputAlpha.scale, info.stage2outputAlpha.bias, info.stage2outputAlpha.abDotProduct,850info.stage2outputAlpha.cdDotProduct, info.stage2outputAlpha.muxSum);851}852}853854for( i=0; i<7; i++ )855{856pglFinalCombinerInputNV(info.finalStage[i].variable, info.finalStage[i].input,857info.finalStage[i].mapping, info.finalStage[i].componentUsage );858}859}860861GLenum COGLColorCombinerNvidia::ConstMap(uint8 c)862{863switch(c)864{865case MUX_0:866return GL_ZERO;867case MUX_1:868return GL_ZERO;869case MUX_COMBINED:870case MUX_TEXEL0:871case MUX_TEXEL1:872case MUX_PRIM:873case MUX_SHADE:874case MUX_ENV:875case MUX_COMBALPHA:876case MUX_T0_ALPHA:877case MUX_T1_ALPHA:878case MUX_PRIM_ALPHA:879case MUX_SHADE_ALPHA:880case MUX_ENV_ALPHA:881case MUX_LODFRAC:882case MUX_PRIMLODFRAC:883break;884}885return GL_ZERO;886887}888889void Set1Variable(GLenum variable, uint8 val, NVCombinerInputType &record, const NVRegisterCombinerParserType &result, bool forRGB=true)890{891record.variable = variable;892record.componentUsage = RGBmap1[val&MUX_MASK].componentUsage;893record.input = RGBmap1[val&MUX_MASK].input;894record.mapping = RGBmap1[val&MUX_MASK].mapping;895896switch( val&MUX_MASK )897{898case MUX_PRIM:899case MUX_ENV:900case MUX_PRIMLODFRAC:901case MUX_LODFRAC:902if( (val&MUX_MASK) == result.constant0 )903{904record.input = GL_CONSTANT_COLOR0_NV;905}906else if( (val&MUX_MASK) == result.constant1 )907{908record.input = GL_CONSTANT_COLOR1_NV;909}910else911{912record.input = GL_ZERO;913}914break;915}916917if( val&MUX_NEG )918{919record.mapping = GL_SIGNED_NEGATE_NV;920}921else if( val == MUX_1 )922{923record.mapping = GL_UNSIGNED_INVERT_NV;924}925else if( val & MUX_COMPLEMENT )926{927record.mapping = GL_UNSIGNED_INVERT_NV;928}929930if( val & MUX_ALPHAREPLICATE || !forRGB )931{932record.componentUsage = GL_ALPHA;933}934}935936int COGLColorCombinerNvidia::SaveParserResult(const NVRegisterCombinerParserType &result)937{938NVRegisterCombinerSettingType save;939940// Stage 1 RGB941Set1Variable(GL_VARIABLE_A_NV, result.s1rgb.a, save.stage1RGB[0], result);942Set1Variable(GL_VARIABLE_B_NV, result.s1rgb.b, save.stage1RGB[1], result);943Set1Variable(GL_VARIABLE_C_NV, result.s1rgb.c, save.stage1RGB[2], result);944Set1Variable(GL_VARIABLE_D_NV, result.s1rgb.d, save.stage1RGB[3], result);945946// Stage 1 Alpha947Set1Variable(GL_VARIABLE_A_NV, result.s1alpha.a, save.stage1Alpha[0], result, false);948Set1Variable(GL_VARIABLE_B_NV, result.s1alpha.b, save.stage1Alpha[1], result, false);949Set1Variable(GL_VARIABLE_C_NV, result.s1alpha.c, save.stage1Alpha[2], result, false);950Set1Variable(GL_VARIABLE_D_NV, result.s1alpha.d, save.stage1Alpha[3], result, false);951952// Stage 2 RGB953Set1Variable(GL_VARIABLE_A_NV, result.s2rgb.a, save.stage2RGB[0], result);954Set1Variable(GL_VARIABLE_B_NV, result.s2rgb.b, save.stage2RGB[1], result);955Set1Variable(GL_VARIABLE_C_NV, result.s2rgb.c, save.stage2RGB[2], result);956Set1Variable(GL_VARIABLE_D_NV, result.s2rgb.d, save.stage2RGB[3], result);957958// Stage 2 Alpha959Set1Variable(GL_VARIABLE_A_NV, result.s2alpha.a, save.stage2Alpha[0], result, false);960Set1Variable(GL_VARIABLE_B_NV, result.s2alpha.b, save.stage2Alpha[1], result, false);961Set1Variable(GL_VARIABLE_C_NV, result.s2alpha.c, save.stage2Alpha[2], result, false);962Set1Variable(GL_VARIABLE_D_NV, result.s2alpha.d, save.stage2Alpha[3], result, false);963964// Final Stage RGB965Set1Variable(GL_VARIABLE_A_NV, result.finalrgb.a, save.finalStage[0], result);966Set1Variable(GL_VARIABLE_B_NV, result.finalrgb.b, save.finalStage[1], result);967Set1Variable(GL_VARIABLE_C_NV, result.finalrgb.c, save.finalStage[2], result);968Set1Variable(GL_VARIABLE_D_NV, result.finalrgb.d, save.finalStage[3], result);969Set1Variable(GL_VARIABLE_E_NV, result.finalrgb.e, save.finalStage[4], result);970//save.finalStage[4].componentUsage = GL_ALPHA;971Set1Variable(GL_VARIABLE_F_NV, result.finalrgb.f, save.finalStage[5], result);972//save.finalStage[5].componentUsage = GL_ALPHA;973Set1Variable(GL_VARIABLE_G_NV, result.finalrgb.g, save.finalStage[6], result);974save.finalStage[6].componentUsage = GL_ALPHA;975976save.numOfStages = result.stagesUsed;977save.dwMux0 = m_pDecodedMux->m_dwMux0;978save.dwMux1 = m_pDecodedMux->m_dwMux1;979980save.stage1outputRGB.scale = GL_NONE;981save.stage1outputRGB.sumOutput = GL_SPARE0_NV;982save.stage1outputRGB.abDotProduct = GL_FALSE;983save.stage1outputRGB.cdDotProduct = GL_FALSE;984save.stage1outputRGB.abOutput = GL_SPARE1_NV;985save.stage1outputRGB.cdOutput = GL_SECONDARY_COLOR_NV;986save.stage1outputRGB.bias = GL_NONE;987save.stage1outputRGB.muxSum = GL_FALSE;988989save.stage1outputAlpha.scale = GL_NONE;990save.stage1outputAlpha.sumOutput = GL_SPARE0_NV;991save.stage1outputAlpha.abDotProduct = GL_FALSE;992save.stage1outputAlpha.cdDotProduct = GL_FALSE;993save.stage1outputAlpha.abOutput = GL_SPARE1_NV;994save.stage1outputAlpha.cdOutput = GL_SECONDARY_COLOR_NV;995save.stage1outputAlpha.bias = GL_NONE;996save.stage1outputAlpha.muxSum = GL_FALSE;997998save.stage2outputRGB.scale = GL_NONE;999save.stage2outputRGB.sumOutput = GL_SPARE0_NV;1000save.stage2outputRGB.abDotProduct = GL_FALSE;1001save.stage2outputRGB.cdDotProduct = GL_FALSE;1002save.stage2outputRGB.abOutput = GL_SPARE1_NV;1003save.stage2outputRGB.cdOutput = GL_SECONDARY_COLOR_NV;1004save.stage2outputRGB.bias = GL_NONE;1005save.stage2outputRGB.muxSum = GL_FALSE;10061007save.stage2outputAlpha.scale = GL_NONE;1008save.stage2outputAlpha.sumOutput = GL_SPARE0_NV;1009save.stage2outputAlpha.abDotProduct = GL_FALSE;1010save.stage2outputAlpha.cdDotProduct = GL_FALSE;1011save.stage2outputAlpha.abOutput = GL_SPARE1_NV;1012save.stage2outputAlpha.cdOutput = GL_SECONDARY_COLOR_NV;1013save.stage2outputAlpha.bias = GL_NONE;1014save.stage2outputAlpha.muxSum = GL_FALSE;10151016save.constant0 = result.constant0;1017save.constant1 = result.constant1;10181019#ifdef DEBUGGER1020memcpy(&(save.parseResult),&result, sizeof(result));1021if( logCombiners )1022{1023TRACE0("\nNew Mux:\n");1024DisplayMuxString();1025COGLColorCombiner::DisplaySimpleMuxString();1026DisplayNVCombinerString(save);1027}1028#endif10291030m_vCompiledSettings.push_back(save);10311032return m_vCompiledSettings.size()-1; // Return the index of the last element1033}103410351036void COGLColorCombinerNvidia::DisableCombiner(void)1037{1038glDisable(GL_REGISTER_COMBINERS_NV);1039COGLColorCombiner4::DisableCombiner();1040}10411042void COGLColorCombinerNvidia::InitCombinerCycleCopy(void)1043{1044glDisable(GL_REGISTER_COMBINERS_NV);1045COGLColorCombiner4::InitCombinerCycleCopy();1046}10471048void COGLColorCombinerNvidia::InitCombinerCycleFill(void)1049{1050glDisable(GL_REGISTER_COMBINERS_NV);1051COGLColorCombiner4::InitCombinerCycleFill();1052}10531054void COGLColorCombinerNvidia::InitCombinerBlenderForSimpleTextureDraw(uint32 tile)1055{1056glDisable(GL_REGISTER_COMBINERS_NV);1057COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile);1058}10591060void COGLColorCombinerNvidia::ApplyFogAtFinalStage()1061{1062// If we need to enable fog at final stage, the current flag stage setting1063// will be affect, which means correct combiner setting at final stage is lost1064// in order to use fog1065if( glIsEnabled(GL_FOG) )1066{1067// Use final stage as: cmb*fogfactor+fog*(1-fogfactor)1068pglFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_FOG, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );1069pglFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );1070pglFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_FOG, GL_UNSIGNED_IDENTITY_NV, GL_RGB );1071pglFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );1072}1073}10741075#ifdef DEBUGGER1076extern const char *translatedCombTypes[];1077void COGLColorCombinerNvidia::DisplaySimpleMuxString(void)1078{1079COGLColorCombiner::DisplaySimpleMuxString();1080TRACE0("\nNV Combiner setting\n");1081uint32 index = FindCompiledMux();1082if( index >= 0 )1083{1084NVRegisterCombinerSettingType &record = m_vCompiledSettings[index];1085DisplayNVCombinerString(record);1086}1087}10881089char* FormatStrForFinalStage(uint8 val, char* buf)1090{1091if( (val&MUX_MASK) == MUX_E_F )1092{1093strcpy(buf, "E_F");1094return buf;1095}1096else1097return DecodedMux::FormatStr(val, buf);1098}10991100void COGLColorCombinerNvidia::DisplayNVCombinerString(NVRegisterCombinerSettingType &record)1101{1102NVRegisterCombinerParserType &result = record.parseResult;11031104char buf[2000];1105char buf0[30];1106char buf1[30];1107char buf2[30];1108char buf3[30];1109char buf4[30];1110char buf5[30];1111char buf6[30];1112buf[0]='\0';11131114TRACE0("\n\n");1115TRACE0("\nNvidia combiner stages:\n");11161117DebuggerAppendMsg("//aRGB0:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s1rgb.a, buf0),1118DecodedMux::FormatStr(result.s1rgb.b, buf1), DecodedMux::FormatStr(result.s1rgb.c, buf2),DecodedMux::FormatStr(result.s1rgb.d, buf3));1119DebuggerAppendMsg("//aA0:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s1alpha.a, buf0),1120DecodedMux::FormatStr(result.s1alpha.b, buf1), DecodedMux::FormatStr(result.s1alpha.c, buf2),DecodedMux::FormatStr(result.s1alpha.d, buf3));1121if( record.numOfStages == 2 )1122{1123DebuggerAppendMsg("//aRGB1:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s2rgb.a, buf0),1124DecodedMux::FormatStr(result.s2rgb.b, buf1), DecodedMux::FormatStr(result.s2rgb.c, buf2),DecodedMux::FormatStr(result.s2rgb.d, buf3));1125DebuggerAppendMsg("//aA1:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s2alpha.a, buf0),1126DecodedMux::FormatStr(result.s2alpha.b, buf1), DecodedMux::FormatStr(result.s2alpha.c, buf2),DecodedMux::FormatStr(result.s2alpha.d, buf3));1127}1128DebuggerAppendMsg("//Final:\t%s * %s + (1 - %s) * %s + %s\n\tE=%s, F=%s\n", FormatStrForFinalStage(result.finalrgb.a, buf0),1129FormatStrForFinalStage(result.finalrgb.b, buf1), FormatStrForFinalStage(result.finalrgb.a, buf2),1130FormatStrForFinalStage(result.finalrgb.c, buf3), FormatStrForFinalStage(result.finalrgb.d, buf4),1131FormatStrForFinalStage(result.finalrgb.e, buf5), FormatStrForFinalStage(result.finalrgb.f, buf6));11321133if( result.constant0 != MUX_0 )1134{1135DebuggerAppendMsg("//Constant 0:\t%s\n", DecodedMux::FormatStr(result.constant0, buf0));1136}1137if( result.constant1 != MUX_0 )1138{1139DebuggerAppendMsg("//Constant 1:\t%s\n", DecodedMux::FormatStr(result.constant1, buf0));1140}1141TRACE0("\n\n");1142}11431144#endif1145114611471148