2 Copyright (C) 2003 Rice1964
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include "OGLExtensions.h"
21 #include "OGLFragmentShaders.h"
22 #include "OGLRender.h"
23 #include "OGLGraphicsContext.h"
25 COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender)
26 : COGLColorCombiner(pRender)
28 m_bShaderIsSupported = false;
30 COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner()
34 bool COGLFragmentShaderCombiner::Initialize(void)
36 if( !COGLColorCombiner::Initialize() )
39 COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);
40 if( pcontext->IsExtensionSupported("GL_ARB_fragment_shader") )
42 m_bShaderIsSupported = true;
48 void COGLFragmentShaderCombiner::InitCombinerCycle12(void)
51 void COGLFragmentShaderCombiner::DisableCombiner(void)
53 COGLColorCombiner::DisableCombiner();
56 void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void)
58 COGLColorCombiner::InitCombinerCycleCopy();
61 void COGLFragmentShaderCombiner::InitCombinerCycleFill(void)
63 COGLColorCombiner::InitCombinerCycleFill();
65 void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile)
67 COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile);
71 void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void)
73 COGLColorCombiner::DisplaySimpleMuxString();
79 COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender)
80 : COGLColorCombiner4(pRender)
83 m_pDecodedMux = new DecodedMuxForPixelShader;
84 m_bFragmentProgramIsSupported = false;
86 COGL_FragmentProgramCombiner::~COGL_FragmentProgramCombiner()
88 int size = m_vCompiledShaders.size();
89 for (int i=0; i<size; i++)
91 GLuint ID = m_vCompiledShaders[i].programID;
92 pglDeleteProgramsARB(1, &ID);
94 m_vCompiledShaders[i].programID = 0;
97 m_vCompiledShaders.clear();
100 bool COGL_FragmentProgramCombiner::Initialize(void)
102 if( !COGLColorCombiner4::Initialize() )
105 COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);
106 if( pcontext->IsExtensionSupported("GL_ARB_fragment_program") )
108 m_bFragmentProgramIsSupported = true;
116 void COGL_FragmentProgramCombiner::DisableCombiner(void)
118 glDisable(GL_FRAGMENT_PROGRAM_ARB);
120 COGLColorCombiner4::DisableCombiner();
123 void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void)
125 glDisable(GL_FRAGMENT_PROGRAM_ARB);
127 COGLColorCombiner4::InitCombinerCycleCopy();
130 void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void)
132 glDisable(GL_FRAGMENT_PROGRAM_ARB);
134 COGLColorCombiner4::InitCombinerCycleFill();
137 const char *muxToFP_Maps[][2] = {
139 {"0", "0"}, //MUX_0 = 0,
141 {"comb", "comb.a"}, //MUX_COMBINED,
142 {"t0", "t0.a"}, //MUX_TEXEL0,
143 {"t1", "t1.a"}, //MUX_TEXEL1,
144 {"program.env[2]", "program.env[2].a"}, //MUX_PRIM,
145 {"fragment.color", "fragment.color.a"}, //MUX_SHADE,
146 {"program.env[1]", "program.env[1].a"}, //MUX_ENV,
147 {"comb.a", "comb.a"}, //MUX_COMBALPHA,
148 {"t0.a", "t0.a"}, //MUX_T0_ALPHA,
149 {"t1.a", "t1.a"}, //MUX_T1_ALPHA,
150 {"primcolor.a", "primcolor.a"}, //MUX_PRIM_ALPHA,
151 {"fragment.color.a", "fragment.color.a"}, //MUX_SHADE_ALPHA,
152 {"envcolor.a", "envcolor.a"}, //MUX_ENV_ALPHA,
153 {"program.env[3]", "program.env[3]"}, //MUX_LODFRAC,
154 {"program.env[4]", "program.env[4]"}, //MUX_PRIMLODFRAC,
155 {"1", "1"}, //MUX_K5,
156 {"1", "1"}, //MUX_UNK, // Should not be used
160 const char *oglFPTest =
168 "ATTRIB coord0 = fragment.texcoord[0];\n"
169 "ATTRIB coord1 = fragment.texcoord[1];\n"
170 "ATTRIB shade = fragment.color;\n"
171 "ATTRIB fogfactor = fragment.fogcoord;\n"
173 "OUTPUT out = result.color;\n"
176 "TEX t0, coord0, texture[0], 2D;\n"
177 "TEX t1, coord1, texture[1], 2D;\n"
179 "MAD_SAT out, t0, program.env[1],program.env[0];\n"
180 //"SUB comb.rgb, t0, 0;\n"
181 //"MAD_SAT out.rgb, comb, program.env[1], 0;\n"
182 //"SUB comb.a, t0, 0;\n"
183 //"MAD_SAT out.a, comb, program.env[1], 0;\n"
188 char* MuxToOC(uint8 val)
191 if( val&MUX_ALPHAREPLICATE )
192 return (char*)muxToFP_Maps[val&0x1F][1];
194 return (char*)muxToFP_Maps[val&0x1F][0];
197 char* MuxToOA(uint8 val)
200 return (char*)muxToFP_Maps[val&0x1F][0];
203 static void CheckFpVars(uint8 MuxVar, bool &bNeedT0, bool &bNeedT1)
206 if (MuxVar == MUX_TEXEL0 || MuxVar == MUX_T0_ALPHA)
208 if (MuxVar == MUX_TEXEL1 || MuxVar == MUX_T1_ALPHA)
212 void COGL_FragmentProgramCombiner::GenerateProgramStr()
214 DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux;
216 mux.splitType[0] = mux.splitType[1] = mux.splitType[2] = mux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED;
217 m_pDecodedMux->Reformat(false);
219 char tempstr[500], newFPBody[4092];
220 bool bNeedT0 = false, bNeedT1 = false, bNeedComb2 = false;
223 for( int cycle=0; cycle<2; cycle++ )
225 for( int channel=0; channel<2; channel++)
227 char* (*func)(uint8) = channel==0?MuxToOC:MuxToOA;
228 char *dst = channel==0?(char*)"rgb":(char*)"a";
229 N64CombinerType &m = mux.m_n64Combiners[cycle*2+channel];
230 switch( mux.splitType[cycle*2+channel] )
232 case CM_FMT_TYPE_NOT_USED:
236 sprintf(tempstr, "MOV comb.%s, %s;\n", dst, func(m.d));
237 CheckFpVars(m.d, bNeedT0, bNeedT1);
239 case CM_FMT_TYPE_A_MOD_C:
240 sprintf(tempstr, "MUL comb.%s, %s, %s;\n", dst, func(m.a), func(m.c));
241 CheckFpVars(m.a, bNeedT0, bNeedT1);
242 CheckFpVars(m.c, bNeedT0, bNeedT1);
244 case CM_FMT_TYPE_A_ADD_D:
245 sprintf(tempstr, "ADD_SAT comb.%s, %s, %s;\n", dst, func(m.a), func(m.d));
246 CheckFpVars(m.a, bNeedT0, bNeedT1);
247 CheckFpVars(m.d, bNeedT0, bNeedT1);
249 case CM_FMT_TYPE_A_SUB_B:
250 sprintf(tempstr, "SUB comb.%s, %s, %s;\n", dst, func(m.a), func(m.b));
251 CheckFpVars(m.a, bNeedT0, bNeedT1);
252 CheckFpVars(m.b, bNeedT0, bNeedT1);
254 case CM_FMT_TYPE_A_MOD_C_ADD_D:
255 sprintf(tempstr, "MAD_SAT comb.%s, %s, %s, %s;\n", dst, func(m.a), func(m.c), func(m.d));
256 CheckFpVars(m.a, bNeedT0, bNeedT1);
257 CheckFpVars(m.c, bNeedT0, bNeedT1);
258 CheckFpVars(m.d, bNeedT0, bNeedT1);
260 case CM_FMT_TYPE_A_LERP_B_C:
261 sprintf(tempstr, "LRP_SAT comb.%s, %s, %s, %s;\n", dst, func(m.c), func(m.a), func(m.b));
262 CheckFpVars(m.a, bNeedT0, bNeedT1);
263 CheckFpVars(m.b, bNeedT0, bNeedT1);
264 CheckFpVars(m.c, bNeedT0, bNeedT1);
265 //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));
268 sprintf(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));
269 CheckFpVars(m.a, bNeedT0, bNeedT1);
270 CheckFpVars(m.b, bNeedT0, bNeedT1);
271 CheckFpVars(m.c, bNeedT0, bNeedT1);
272 CheckFpVars(m.d, bNeedT0, bNeedT1);
276 strcat(newFPBody, tempstr);
280 strcpy(oglNewFP, "!!ARBfp1.0\n");
281 strcat(oglNewFP, "#Declarations\n");
282 if (gRDP.bFogEnableInBlender && gRSP.bFogEnabled)
283 strcat(oglNewFP, "OPTION ARB_fog_linear;\n");
285 strcat(oglNewFP, "TEMP t0;\n");
287 strcat(oglNewFP, "TEMP t1;\n");
288 strcat(oglNewFP, "TEMP comb;\n");
290 strcat(oglNewFP, "TEMP comb2;\n");
291 strcat(oglNewFP, "#Instructions\n");
293 strcat(oglNewFP, "TEX t0, fragment.texcoord[0], texture[0], 2D;\n");
295 strcat(oglNewFP, "TEX t1, fragment.texcoord[1], texture[1], 2D;\n");
296 strcat(oglNewFP, "# N64 cycle 1, result is in comb\n");
298 strcat(oglNewFP, newFPBody);
300 strcat(oglNewFP, "MOV result.color, comb;\n");
301 strcat(oglNewFP, "END\n\n");
304 int COGL_FragmentProgramCombiner::ParseDecodedMux()
306 if( !m_bFragmentProgramIsSupported )
307 return COGLColorCombiner4::ParseDecodedMux();
309 OGLShaderCombinerSaveType res;
311 pglGenProgramsARB( 1, &res.programID);
313 pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, res.programID);
315 GenerateProgramStr();
317 pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglNewFP), oglNewFP);
319 //pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglFPTest), oglFPTest);
321 if (glGetError() != 0)
325 char *str = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
327 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &position);
331 if( m_lastIndex >= 0 ) COGLColorCombiner4::DisplaySimpleMuxString();
332 DebugMessage(M64MSG_ERROR, "%s - %s", str, oglNewFP+position);
334 glDisable(GL_FRAGMENT_PROGRAM_ARB);
335 return COGLColorCombiner4::ParseDecodedMux();
339 glEnable(GL_FRAGMENT_PROGRAM_ARB);
341 res.dwMux0 = m_pDecodedMux->m_dwMux0;
342 res.dwMux1 = m_pDecodedMux->m_dwMux1;
343 res.fogIsUsed = gRDP.bFogEnableInBlender && gRSP.bFogEnabled;
345 m_vCompiledShaders.push_back(res);
346 m_lastIndex = m_vCompiledShaders.size()-1;
351 void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index)
353 GLuint ID = m_vCompiledShaders[index].programID;
354 pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ID );
356 glEnable(GL_FRAGMENT_PROGRAM_ARB);
360 void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index)
363 pf = GetEnvColorfv();
364 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, pf);
366 pf = GetPrimitiveColorfv();
367 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 2, pf);
370 float frac = gRDP.LODFrac / 255.0f;
371 float tempf[4] = {frac,frac,frac,frac};
372 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 3, tempf);
375 float frac2 = gRDP.primLODFrac / 255.0f;
376 float tempf2[4] = {frac2,frac2,frac2,frac2};
377 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 4, tempf2);
380 float tempf3[4] = {0,0,0,0};
381 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, tempf3);
383 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 6, tempf3);
387 int COGL_FragmentProgramCombiner::FindCompiledMux()
390 if( debuggerDropCombiners )
392 m_vCompiledShaders.clear();
393 //m_dwLastMux0 = m_dwLastMux1 = 0;
394 debuggerDropCombiners = false;
397 for( uint32 i=0; i<m_vCompiledShaders.size(); i++ )
399 if( m_vCompiledShaders[i].dwMux0 == m_pDecodedMux->m_dwMux0
400 && m_vCompiledShaders[i].dwMux1 == m_pDecodedMux->m_dwMux1
401 && m_vCompiledShaders[i].fogIsUsed == (gRDP.bFogEnableInBlender && gRSP.bFogEnabled) )
408 //////////////////////////////////////////////////////////////////////////
409 void COGL_FragmentProgramCombiner::InitCombinerCycle12(void)
411 if( !m_bFragmentProgramIsSupported )
413 COGLColorCombiner4::InitCombinerCycle12();
418 if( debuggerDropCombiners )
420 UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1);
421 m_vCompiledShaders.clear();
422 m_dwLastMux0 = m_dwLastMux1 = 0;
423 debuggerDropCombiners = false;
427 m_pOGLRender->EnableMultiTexture();
429 bool combinerIsChanged = false;
431 if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 )
433 combinerIsChanged = true;
434 m_lastIndex = FindCompiledMux();
435 if( m_lastIndex < 0 ) // Can not found
437 m_lastIndex = ParseDecodedMux();
440 m_dwLastMux0 = m_pDecodedMux->m_dwMux0;
441 m_dwLastMux1 = m_pDecodedMux->m_dwMux1;
445 GenerateCombinerSettingConstants(m_lastIndex);
446 if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded )
448 if( m_bCycleChanged || combinerIsChanged )
450 GenerateCombinerSettingConstants(m_lastIndex);
451 GenerateCombinerSetting(m_lastIndex);
453 else if( gRDP.colorsAreReloaded )
455 GenerateCombinerSettingConstants(m_lastIndex);
458 m_pOGLRender->SetAllTexelRepeatFlag();
460 gRDP.colorsAreReloaded = false;
461 gRDP.texturesAreReloaded = false;
465 m_pOGLRender->SetAllTexelRepeatFlag();
470 void COGL_FragmentProgramCombiner::DisplaySimpleMuxString(void)
472 COGLColorCombiner::DisplaySimpleMuxString();
473 DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux;
475 GenerateProgramStr();
476 //sprintf(oglNewFP, oglFP,
477 // MuxToOC(mux.aRGB0), MuxToOC(mux.bRGB0), MuxToOC(mux.cRGB0), MuxToOC(mux.dRGB0),
478 // MuxToOA(mux.aA0), MuxToOA(mux.bA0), MuxToOA(mux.cA0), MuxToOA(mux.dA0),
479 // MuxToOC(mux.aRGB1), MuxToOC(mux.bRGB1), MuxToOC(mux.cRGB1), MuxToOC(mux.dRGB1),
480 // MuxToOA(mux.aA1), MuxToOA(mux.bA1), MuxToOA(mux.cA1), MuxToOA(mux.dA1)
483 TRACE0("OGL Fragment Program:");