Path: blob/master/libmupen64plus/mupen64plus-video-rice/src/OGLFragmentShaders.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"19#include "OGLDebug.h"20#include "OGLFragmentShaders.h"21#include "OGLRender.h"22#include "OGLGraphicsContext.h"2324COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender)25: COGLColorCombiner(pRender)26{27m_bShaderIsSupported = false;28}29COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner()30{31}3233bool COGLFragmentShaderCombiner::Initialize(void)34{35if( !COGLColorCombiner::Initialize() )36return false;3738COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);39if( pcontext->IsExtensionSupported("GL_ARB_fragment_shader") )40{41m_bShaderIsSupported = true;42}4344return true;45}4647void COGLFragmentShaderCombiner::InitCombinerCycle12(void)48{49}50void COGLFragmentShaderCombiner::DisableCombiner(void)51{52COGLColorCombiner::DisableCombiner();53}5455void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void)56{57COGLColorCombiner::InitCombinerCycleCopy();58}5960void COGLFragmentShaderCombiner::InitCombinerCycleFill(void)61{62COGLColorCombiner::InitCombinerCycleFill();63}64void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile)65{66COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile);67}6869#ifdef DEBUGGER70void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void)71{72COGLColorCombiner::DisplaySimpleMuxString();73}74#endif75767778COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender)79: COGLColorCombiner4(pRender)80{81delete m_pDecodedMux;82m_pDecodedMux = new DecodedMuxForPixelShader;83m_bFragmentProgramIsSupported = false;84}85COGL_FragmentProgramCombiner::~COGL_FragmentProgramCombiner()86{87int size = m_vCompiledShaders.size();88for (int i=0; i<size; i++)89{90GLuint ID = m_vCompiledShaders[i].programID;91pglDeleteProgramsARB(1, &ID);92OPENGL_CHECK_ERRORS;93m_vCompiledShaders[i].programID = 0;94}9596m_vCompiledShaders.clear();97}9899bool COGL_FragmentProgramCombiner::Initialize(void)100{101if( !COGLColorCombiner4::Initialize() )102return false;103104COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);105if( pcontext->IsExtensionSupported("GL_ARB_fragment_program") )106{107m_bFragmentProgramIsSupported = true;108}109110return true;111}112113114115void COGL_FragmentProgramCombiner::DisableCombiner(void)116{117glDisable(GL_FRAGMENT_PROGRAM_ARB);118OPENGL_CHECK_ERRORS;119COGLColorCombiner4::DisableCombiner();120}121122void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void)123{124glDisable(GL_FRAGMENT_PROGRAM_ARB);125OPENGL_CHECK_ERRORS;126COGLColorCombiner4::InitCombinerCycleCopy();127}128129void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void)130{131glDisable(GL_FRAGMENT_PROGRAM_ARB);132OPENGL_CHECK_ERRORS;133COGLColorCombiner4::InitCombinerCycleFill();134}135136const char *muxToFP_Maps[][2] = {137//color -- alpha138{"0", "0"}, //MUX_0 = 0,139{"1", "1"}, //MUX_1,140{"comb", "comb.a"}, //MUX_COMBINED,141{"t0", "t0.a"}, //MUX_TEXEL0,142{"t1", "t1.a"}, //MUX_TEXEL1,143{"program.env[2]", "program.env[2].a"}, //MUX_PRIM,144{"fragment.color", "fragment.color.a"}, //MUX_SHADE,145{"program.env[1]", "program.env[1].a"}, //MUX_ENV,146{"comb.a", "comb.a"}, //MUX_COMBALPHA,147{"t0.a", "t0.a"}, //MUX_T0_ALPHA,148{"t1.a", "t1.a"}, //MUX_T1_ALPHA,149{"primcolor.a", "primcolor.a"}, //MUX_PRIM_ALPHA,150{"fragment.color.a", "fragment.color.a"}, //MUX_SHADE_ALPHA,151{"envcolor.a", "envcolor.a"}, //MUX_ENV_ALPHA,152{"program.env[3]", "program.env[3]"}, //MUX_LODFRAC,153{"program.env[4]", "program.env[4]"}, //MUX_PRIMLODFRAC,154{"1", "1"}, //MUX_K5,155{"1", "1"}, //MUX_UNK, // Should not be used156};157158159const char *oglFPTest =160"!!ARBfp1.0\n"161"#Declarations\n"162"TEMP t0;\n"163"TEMP t1;\n"164"TEMP comb;\n"165"TEMP comb2;\n"166"\n"167"ATTRIB coord0 = fragment.texcoord[0];\n"168"ATTRIB coord1 = fragment.texcoord[1];\n"169"ATTRIB shade = fragment.color;\n"170"ATTRIB fogfactor = fragment.fogcoord;\n"171"\n"172"OUTPUT out = result.color;\n"173"\n"174"#Instructions\n"175"TEX t0, coord0, texture[0], 2D;\n"176"TEX t1, coord1, texture[1], 2D;\n"177"\n"178"MAD_SAT out, t0, program.env[1],program.env[0];\n"179//"SUB comb.rgb, t0, 0;\n"180//"MAD_SAT out.rgb, comb, program.env[1], 0;\n"181//"SUB comb.a, t0, 0;\n"182//"MAD_SAT out.a, comb, program.env[1], 0;\n"183"END\n";184185char oglNewFP[4092];186187char* MuxToOC(uint8 val)188{189// For color channel190if( val&MUX_ALPHAREPLICATE )191return (char*)muxToFP_Maps[val&0x1F][1];192else193return (char*)muxToFP_Maps[val&0x1F][0];194}195196char* MuxToOA(uint8 val)197{198// For alpha channel199return (char*)muxToFP_Maps[val&0x1F][0];200}201202static void CheckFpVars(uint8 MuxVar, bool &bNeedT0, bool &bNeedT1)203{204MuxVar &= 0x1f;205if (MuxVar == MUX_TEXEL0 || MuxVar == MUX_T0_ALPHA)206bNeedT0 = true;207if (MuxVar == MUX_TEXEL1 || MuxVar == MUX_T1_ALPHA)208bNeedT1 = true;209}210211void COGL_FragmentProgramCombiner::GenerateProgramStr()212{213DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux;214215mux.splitType[0] = mux.splitType[1] = mux.splitType[2] = mux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED;216m_pDecodedMux->Reformat(false);217218char tempstr[500], newFPBody[4092];219bool bNeedT0 = false, bNeedT1 = false, bNeedComb2 = false;220newFPBody[0] = 0;221222for( int cycle=0; cycle<2; cycle++ )223{224for( int channel=0; channel<2; channel++)225{226char* (*func)(uint8) = channel==0?MuxToOC:MuxToOA;227char *dst = channel==0?(char*)"rgb":(char*)"a";228N64CombinerType &m = mux.m_n64Combiners[cycle*2+channel];229switch( mux.splitType[cycle*2+channel] )230{231case CM_FMT_TYPE_NOT_USED:232tempstr[0] = 0;233break;234case CM_FMT_TYPE_D:235sprintf(tempstr, "MOV comb.%s, %s;\n", dst, func(m.d));236CheckFpVars(m.d, bNeedT0, bNeedT1);237break;238case CM_FMT_TYPE_A_MOD_C:239sprintf(tempstr, "MUL comb.%s, %s, %s;\n", dst, func(m.a), func(m.c));240CheckFpVars(m.a, bNeedT0, bNeedT1);241CheckFpVars(m.c, bNeedT0, bNeedT1);242break;243case CM_FMT_TYPE_A_ADD_D:244sprintf(tempstr, "ADD_SAT comb.%s, %s, %s;\n", dst, func(m.a), func(m.d));245CheckFpVars(m.a, bNeedT0, bNeedT1);246CheckFpVars(m.d, bNeedT0, bNeedT1);247break;248case CM_FMT_TYPE_A_SUB_B:249sprintf(tempstr, "SUB comb.%s, %s, %s;\n", dst, func(m.a), func(m.b));250CheckFpVars(m.a, bNeedT0, bNeedT1);251CheckFpVars(m.b, bNeedT0, bNeedT1);252break;253case CM_FMT_TYPE_A_MOD_C_ADD_D:254sprintf(tempstr, "MAD_SAT comb.%s, %s, %s, %s;\n", dst, func(m.a), func(m.c), func(m.d));255CheckFpVars(m.a, bNeedT0, bNeedT1);256CheckFpVars(m.c, bNeedT0, bNeedT1);257CheckFpVars(m.d, bNeedT0, bNeedT1);258break;259case CM_FMT_TYPE_A_LERP_B_C:260sprintf(tempstr, "LRP_SAT comb.%s, %s, %s, %s;\n", dst, func(m.c), func(m.a), func(m.b));261CheckFpVars(m.a, bNeedT0, bNeedT1);262CheckFpVars(m.b, bNeedT0, bNeedT1);263CheckFpVars(m.c, bNeedT0, bNeedT1);264//sprintf(tempstr, "SUB comb.%s, %s, %s;\nMAD_SAT comb.%s, comb, %s, %s;\n", dst, func(m.a), func(m.b), dst, func(m.c), func(m.b));265break;266default:267sprintf(tempstr, "SUB comb2.%s, %s, %s;\nMAD_SAT comb.%s, comb2, %s, %s;\n", dst, func(m.a), func(m.b), dst, func(m.c), func(m.d));268CheckFpVars(m.a, bNeedT0, bNeedT1);269CheckFpVars(m.b, bNeedT0, bNeedT1);270CheckFpVars(m.c, bNeedT0, bNeedT1);271CheckFpVars(m.d, bNeedT0, bNeedT1);272bNeedComb2 = true;273break;274}275strcat(newFPBody, tempstr);276}277}278279strcpy(oglNewFP, "!!ARBfp1.0\n");280strcat(oglNewFP, "#Declarations\n");281if (gRDP.bFogEnableInBlender && gRSP.bFogEnabled)282strcat(oglNewFP, "OPTION ARB_fog_linear;\n");283if (bNeedT0)284strcat(oglNewFP, "TEMP t0;\n");285if (bNeedT1)286strcat(oglNewFP, "TEMP t1;\n");287strcat(oglNewFP, "TEMP comb;\n");288if (bNeedComb2)289strcat(oglNewFP, "TEMP comb2;\n");290strcat(oglNewFP, "#Instructions\n");291if (bNeedT0)292strcat(oglNewFP, "TEX t0, fragment.texcoord[0], texture[0], 2D;\n");293if (bNeedT1)294strcat(oglNewFP, "TEX t1, fragment.texcoord[1], texture[1], 2D;\n");295strcat(oglNewFP, "# N64 cycle 1, result is in comb\n");296297strcat(oglNewFP, newFPBody);298299strcat(oglNewFP, "MOV result.color, comb;\n");300strcat(oglNewFP, "END\n\n");301}302303int COGL_FragmentProgramCombiner::ParseDecodedMux()304{305if( !m_bFragmentProgramIsSupported )306return COGLColorCombiner4::ParseDecodedMux();307308OGLShaderCombinerSaveType res;309310pglGenProgramsARB( 1, &res.programID);311OPENGL_CHECK_ERRORS;312pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, res.programID);313OPENGL_CHECK_ERRORS;314GenerateProgramStr();315316pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglNewFP), oglNewFP);317OPENGL_CHECK_ERRORS;318//pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglFPTest), oglFPTest);319320if (glGetError() != 0)321{322GLint position;323#ifdef DEBUGGER324char *str = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);325#endif326glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &position);327if( position >= 0 )328{329#ifdef DEBUGGER330if( m_lastIndex >= 0 ) COGLColorCombiner4::DisplaySimpleMuxString();331DebugMessage(M64MSG_ERROR, "%s - %s", str, oglNewFP+position);332#endif333glDisable(GL_FRAGMENT_PROGRAM_ARB);334return COGLColorCombiner4::ParseDecodedMux();335}336}337338glEnable(GL_FRAGMENT_PROGRAM_ARB);339OPENGL_CHECK_ERRORS;340res.dwMux0 = m_pDecodedMux->m_dwMux0;341res.dwMux1 = m_pDecodedMux->m_dwMux1;342res.fogIsUsed = gRDP.bFogEnableInBlender && gRSP.bFogEnabled;343344m_vCompiledShaders.push_back(res);345m_lastIndex = m_vCompiledShaders.size()-1;346347return m_lastIndex;348}349350void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index)351{352GLuint ID = m_vCompiledShaders[index].programID;353pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ID );354OPENGL_CHECK_ERRORS;355glEnable(GL_FRAGMENT_PROGRAM_ARB);356OPENGL_CHECK_ERRORS;357}358359void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index)360{361float *pf;362pf = GetEnvColorfv();363pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, pf);364OPENGL_CHECK_ERRORS;365pf = GetPrimitiveColorfv();366pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 2, pf);367OPENGL_CHECK_ERRORS;368369float frac = gRDP.LODFrac / 255.0f;370float tempf[4] = {frac,frac,frac,frac};371pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 3, tempf);372OPENGL_CHECK_ERRORS;373374float frac2 = gRDP.primLODFrac / 255.0f;375float tempf2[4] = {frac2,frac2,frac2,frac2};376pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 4, tempf2);377OPENGL_CHECK_ERRORS;378379float tempf3[4] = {0,0,0,0};380pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, tempf3);381OPENGL_CHECK_ERRORS;382pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 6, tempf3);383OPENGL_CHECK_ERRORS;384}385386int COGL_FragmentProgramCombiner::FindCompiledMux()387{388#ifdef DEBUGGER389if( debuggerDropCombiners )390{391m_vCompiledShaders.clear();392//m_dwLastMux0 = m_dwLastMux1 = 0;393debuggerDropCombiners = false;394}395#endif396for( uint32 i=0; i<m_vCompiledShaders.size(); i++ )397{398if( m_vCompiledShaders[i].dwMux0 == m_pDecodedMux->m_dwMux0399&& m_vCompiledShaders[i].dwMux1 == m_pDecodedMux->m_dwMux1400&& m_vCompiledShaders[i].fogIsUsed == (gRDP.bFogEnableInBlender && gRSP.bFogEnabled) )401return (int)i;402}403404return -1;405}406407//////////////////////////////////////////////////////////////////////////408void COGL_FragmentProgramCombiner::InitCombinerCycle12(void)409{410if( !m_bFragmentProgramIsSupported )411{412COGLColorCombiner4::InitCombinerCycle12();413return;414}415416#ifdef DEBUGGER417if( debuggerDropCombiners )418{419UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1);420m_vCompiledShaders.clear();421m_dwLastMux0 = m_dwLastMux1 = 0;422debuggerDropCombiners = false;423}424#endif425426m_pOGLRender->EnableMultiTexture();427428bool combinerIsChanged = false;429430if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 )431{432combinerIsChanged = true;433m_lastIndex = FindCompiledMux();434if( m_lastIndex < 0 ) // Can not found435{436m_lastIndex = ParseDecodedMux();437}438439m_dwLastMux0 = m_pDecodedMux->m_dwMux0;440m_dwLastMux1 = m_pDecodedMux->m_dwMux1;441}442443444GenerateCombinerSettingConstants(m_lastIndex);445if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded )446{447if( m_bCycleChanged || combinerIsChanged )448{449GenerateCombinerSettingConstants(m_lastIndex);450GenerateCombinerSetting(m_lastIndex);451}452else if( gRDP.colorsAreReloaded )453{454GenerateCombinerSettingConstants(m_lastIndex);455}456457m_pOGLRender->SetAllTexelRepeatFlag();458459gRDP.colorsAreReloaded = false;460gRDP.texturesAreReloaded = false;461}462else463{464m_pOGLRender->SetAllTexelRepeatFlag();465}466}467468#ifdef DEBUGGER469void COGL_FragmentProgramCombiner::DisplaySimpleMuxString(void)470{471COGLColorCombiner::DisplaySimpleMuxString();472DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux;473mux.Reformat(false);474GenerateProgramStr();475//sprintf(oglNewFP, oglFP,476// MuxToOC(mux.aRGB0), MuxToOC(mux.bRGB0), MuxToOC(mux.cRGB0), MuxToOC(mux.dRGB0),477// MuxToOA(mux.aA0), MuxToOA(mux.bA0), MuxToOA(mux.cA0), MuxToOA(mux.dA0),478// MuxToOC(mux.aRGB1), MuxToOC(mux.bRGB1), MuxToOC(mux.cRGB1), MuxToOC(mux.dRGB1),479// MuxToOA(mux.aA1), MuxToOA(mux.bA1), MuxToOA(mux.cA1), MuxToOA(mux.dA1)480// );481482TRACE0("OGL Fragment Program:");483TRACE0(oglNewFP);484}485#endif486487488489