Added missing launcher
[mupen64plus-pandora.git] / source / rice_gles / src / OGLFragmentShaders.cpp
CommitLineData
d07c171f 1/*
2Copyright (C) 2003 Rice1964
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*/
18
19#include "OGLExtensions.h"
20#include "OGLDebug.h"
21#include "OGLFragmentShaders.h"
22#include "OGLRender.h"
23#include "OGLGraphicsContext.h"
24
25COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender)
26: COGLColorCombiner(pRender)
27{
28 m_bShaderIsSupported = false;
29}
30COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner()
31{
32}
33
34bool COGLFragmentShaderCombiner::Initialize(void)
35{
36 if( !COGLColorCombiner::Initialize() )
37 return false;
38
39 COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);
40 if( pcontext->IsExtensionSupported("GL_ARB_fragment_shader") )
41 {
42 m_bShaderIsSupported = true;
43 }
44
45 return true;
46}
47
48void COGLFragmentShaderCombiner::InitCombinerCycle12(void)
49{
50}
51void COGLFragmentShaderCombiner::DisableCombiner(void)
52{
53 COGLColorCombiner::DisableCombiner();
54}
55
56void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void)
57{
58 COGLColorCombiner::InitCombinerCycleCopy();
59}
60
61void COGLFragmentShaderCombiner::InitCombinerCycleFill(void)
62{
63 COGLColorCombiner::InitCombinerCycleFill();
64}
65void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile)
66{
67 COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile);
68}
69
70#ifdef DEBUGGER
71void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void)
72{
73 COGLColorCombiner::DisplaySimpleMuxString();
74}
75#endif
76
77
78
79COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender)
80: COGLColorCombiner4(pRender)
81{
82 delete m_pDecodedMux;
83 m_pDecodedMux = new DecodedMuxForPixelShader;
84 m_bFragmentProgramIsSupported = false;
85}
86COGL_FragmentProgramCombiner::~COGL_FragmentProgramCombiner()
87{
88 int size = m_vCompiledShaders.size();
89 for (int i=0; i<size; i++)
90 {
91 GLuint ID = m_vCompiledShaders[i].programID;
92 pglDeleteProgramsARB(1, &ID);
93 OPENGL_CHECK_ERRORS;
94 m_vCompiledShaders[i].programID = 0;
95 }
96
97 m_vCompiledShaders.clear();
98}
99
100bool COGL_FragmentProgramCombiner::Initialize(void)
101{
102 if( !COGLColorCombiner4::Initialize() )
103 return false;
104
105 COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);
106 if( pcontext->IsExtensionSupported("GL_ARB_fragment_program") )
107 {
108 m_bFragmentProgramIsSupported = true;
109 }
110
111 return true;
112}
113
114
115
116void COGL_FragmentProgramCombiner::DisableCombiner(void)
117{
118 glDisable(GL_FRAGMENT_PROGRAM_ARB);
119 OPENGL_CHECK_ERRORS;
120 COGLColorCombiner4::DisableCombiner();
121}
122
123void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void)
124{
125 glDisable(GL_FRAGMENT_PROGRAM_ARB);
126 OPENGL_CHECK_ERRORS;
127 COGLColorCombiner4::InitCombinerCycleCopy();
128}
129
130void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void)
131{
132 glDisable(GL_FRAGMENT_PROGRAM_ARB);
133 OPENGL_CHECK_ERRORS;
134 COGLColorCombiner4::InitCombinerCycleFill();
135}
136
137const char *muxToFP_Maps[][2] = {
138//color -- alpha
139{"0", "0"}, //MUX_0 = 0,
140{"1", "1"}, //MUX_1,
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
157};
158
159
160const char *oglFPTest =
161"!!ARBfp1.0\n"
162"#Declarations\n"
163"TEMP t0;\n"
164"TEMP t1;\n"
165"TEMP comb;\n"
166"TEMP comb2;\n"
167"\n"
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"
172"\n"
173"OUTPUT out = result.color;\n"
174"\n"
175"#Instructions\n"
176"TEX t0, coord0, texture[0], 2D;\n"
177"TEX t1, coord1, texture[1], 2D;\n"
178"\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"
184"END\n";
185
186char oglNewFP[4092];
187
188char* MuxToOC(uint8 val)
189{
190// For color channel
191if( val&MUX_ALPHAREPLICATE )
192 return (char*)muxToFP_Maps[val&0x1F][1];
193else
194 return (char*)muxToFP_Maps[val&0x1F][0];
195}
196
197char* MuxToOA(uint8 val)
198{
199// For alpha channel
200return (char*)muxToFP_Maps[val&0x1F][0];
201}
202
203static void CheckFpVars(uint8 MuxVar, bool &bNeedT0, bool &bNeedT1)
204{
205 MuxVar &= 0x1f;
206 if (MuxVar == MUX_TEXEL0 || MuxVar == MUX_T0_ALPHA)
207 bNeedT0 = true;
208 if (MuxVar == MUX_TEXEL1 || MuxVar == MUX_T1_ALPHA)
209 bNeedT1 = true;
210}
211
212void COGL_FragmentProgramCombiner::GenerateProgramStr()
213{
214 DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux;
215
216 mux.splitType[0] = mux.splitType[1] = mux.splitType[2] = mux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED;
217 m_pDecodedMux->Reformat(false);
218
219 char tempstr[500], newFPBody[4092];
220 bool bNeedT0 = false, bNeedT1 = false, bNeedComb2 = false;
221 newFPBody[0] = 0;
222
223 for( int cycle=0; cycle<2; cycle++ )
224 {
225 for( int channel=0; channel<2; channel++)
226 {
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] )
231 {
232 case CM_FMT_TYPE_NOT_USED:
233 tempstr[0] = 0;
234 break;
235 case CM_FMT_TYPE_D:
236 sprintf(tempstr, "MOV comb.%s, %s;\n", dst, func(m.d));
237 CheckFpVars(m.d, bNeedT0, bNeedT1);
238 break;
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);
243 break;
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);
248 break;
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);
253 break;
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);
259 break;
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));
266 break;
267 default:
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);
273 bNeedComb2 = true;
274 break;
275 }
276 strcat(newFPBody, tempstr);
277 }
278 }
279
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");
284 if (bNeedT0)
285 strcat(oglNewFP, "TEMP t0;\n");
286 if (bNeedT1)
287 strcat(oglNewFP, "TEMP t1;\n");
288 strcat(oglNewFP, "TEMP comb;\n");
289 if (bNeedComb2)
290 strcat(oglNewFP, "TEMP comb2;\n");
291 strcat(oglNewFP, "#Instructions\n");
292 if (bNeedT0)
293 strcat(oglNewFP, "TEX t0, fragment.texcoord[0], texture[0], 2D;\n");
294 if (bNeedT1)
295 strcat(oglNewFP, "TEX t1, fragment.texcoord[1], texture[1], 2D;\n");
296 strcat(oglNewFP, "# N64 cycle 1, result is in comb\n");
297
298 strcat(oglNewFP, newFPBody);
299
300 strcat(oglNewFP, "MOV result.color, comb;\n");
301 strcat(oglNewFP, "END\n\n");
302}
303
304int COGL_FragmentProgramCombiner::ParseDecodedMux()
305{
306 if( !m_bFragmentProgramIsSupported )
307 return COGLColorCombiner4::ParseDecodedMux();
308
309 OGLShaderCombinerSaveType res;
310
311 pglGenProgramsARB( 1, &res.programID);
312 OPENGL_CHECK_ERRORS;
313 pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, res.programID);
314 OPENGL_CHECK_ERRORS;
315 GenerateProgramStr();
316
317 pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglNewFP), oglNewFP);
318 OPENGL_CHECK_ERRORS;
319 //pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglFPTest), oglFPTest);
320
321 if (glGetError() != 0)
322 {
323 GLint position;
324#ifdef DEBUGGER
325 char *str = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
326#endif
327 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &position);
328 if( position >= 0 )
329 {
330#ifdef DEBUGGER
331 if( m_lastIndex >= 0 ) COGLColorCombiner4::DisplaySimpleMuxString();
332 DebugMessage(M64MSG_ERROR, "%s - %s", str, oglNewFP+position);
333#endif
334 glDisable(GL_FRAGMENT_PROGRAM_ARB);
335 return COGLColorCombiner4::ParseDecodedMux();
336 }
337 }
338
339 glEnable(GL_FRAGMENT_PROGRAM_ARB);
340 OPENGL_CHECK_ERRORS;
341 res.dwMux0 = m_pDecodedMux->m_dwMux0;
342 res.dwMux1 = m_pDecodedMux->m_dwMux1;
343 res.fogIsUsed = gRDP.bFogEnableInBlender && gRSP.bFogEnabled;
344
345 m_vCompiledShaders.push_back(res);
346 m_lastIndex = m_vCompiledShaders.size()-1;
347
348 return m_lastIndex;
349}
350
351void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index)
352{
353 GLuint ID = m_vCompiledShaders[index].programID;
354 pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ID );
355 OPENGL_CHECK_ERRORS;
356 glEnable(GL_FRAGMENT_PROGRAM_ARB);
357 OPENGL_CHECK_ERRORS;
358}
359
360void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index)
361{
362 float *pf;
363 pf = GetEnvColorfv();
364 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, pf);
365 OPENGL_CHECK_ERRORS;
366 pf = GetPrimitiveColorfv();
367 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 2, pf);
368 OPENGL_CHECK_ERRORS;
369
370 float frac = gRDP.LODFrac / 255.0f;
371 float tempf[4] = {frac,frac,frac,frac};
372 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 3, tempf);
373 OPENGL_CHECK_ERRORS;
374
375 float frac2 = gRDP.primLODFrac / 255.0f;
376 float tempf2[4] = {frac2,frac2,frac2,frac2};
377 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 4, tempf2);
378 OPENGL_CHECK_ERRORS;
379
380 float tempf3[4] = {0,0,0,0};
381 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, tempf3);
382 OPENGL_CHECK_ERRORS;
383 pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 6, tempf3);
384 OPENGL_CHECK_ERRORS;
385}
386
387int COGL_FragmentProgramCombiner::FindCompiledMux()
388{
389#ifdef DEBUGGER
390 if( debuggerDropCombiners )
391 {
392 m_vCompiledShaders.clear();
393 //m_dwLastMux0 = m_dwLastMux1 = 0;
394 debuggerDropCombiners = false;
395 }
396#endif
397 for( uint32 i=0; i<m_vCompiledShaders.size(); i++ )
398 {
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) )
402 return (int)i;
403 }
404
405 return -1;
406}
407
408//////////////////////////////////////////////////////////////////////////
409void COGL_FragmentProgramCombiner::InitCombinerCycle12(void)
410{
411 if( !m_bFragmentProgramIsSupported )
412 {
413 COGLColorCombiner4::InitCombinerCycle12();
414 return;
415 }
416
417#ifdef DEBUGGER
418 if( debuggerDropCombiners )
419 {
420 UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1);
421 m_vCompiledShaders.clear();
422 m_dwLastMux0 = m_dwLastMux1 = 0;
423 debuggerDropCombiners = false;
424 }
425#endif
426
427 m_pOGLRender->EnableMultiTexture();
428
429 bool combinerIsChanged = false;
430
431 if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 )
432 {
433 combinerIsChanged = true;
434 m_lastIndex = FindCompiledMux();
435 if( m_lastIndex < 0 ) // Can not found
436 {
437 m_lastIndex = ParseDecodedMux();
438 }
439
440 m_dwLastMux0 = m_pDecodedMux->m_dwMux0;
441 m_dwLastMux1 = m_pDecodedMux->m_dwMux1;
442 }
443
444
445 GenerateCombinerSettingConstants(m_lastIndex);
446 if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded )
447 {
448 if( m_bCycleChanged || combinerIsChanged )
449 {
450 GenerateCombinerSettingConstants(m_lastIndex);
451 GenerateCombinerSetting(m_lastIndex);
452 }
453 else if( gRDP.colorsAreReloaded )
454 {
455 GenerateCombinerSettingConstants(m_lastIndex);
456 }
457
458 m_pOGLRender->SetAllTexelRepeatFlag();
459
460 gRDP.colorsAreReloaded = false;
461 gRDP.texturesAreReloaded = false;
462 }
463 else
464 {
465 m_pOGLRender->SetAllTexelRepeatFlag();
466 }
467}
468
469#ifdef DEBUGGER
470void COGL_FragmentProgramCombiner::DisplaySimpleMuxString(void)
471{
472 COGLColorCombiner::DisplaySimpleMuxString();
473 DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux;
474 mux.Reformat(false);
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)
481 // );
482
483 TRACE0("OGL Fragment Program:");
484 TRACE0(oglNewFP);
485}
486#endif
487