Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-video-rice/src/OGLFragmentShaders.cpp
2 views
1
/*
2
Copyright (C) 2003 Rice1964
3
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.
8
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.
13
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.
17
*/
18
19
#include "OGLExtensions.h"
20
#include "OGLDebug.h"
21
#include "OGLFragmentShaders.h"
22
#include "OGLRender.h"
23
#include "OGLGraphicsContext.h"
24
25
COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender)
26
: COGLColorCombiner(pRender)
27
{
28
m_bShaderIsSupported = false;
29
}
30
COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner()
31
{
32
}
33
34
bool 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
48
void COGLFragmentShaderCombiner::InitCombinerCycle12(void)
49
{
50
}
51
void COGLFragmentShaderCombiner::DisableCombiner(void)
52
{
53
COGLColorCombiner::DisableCombiner();
54
}
55
56
void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void)
57
{
58
COGLColorCombiner::InitCombinerCycleCopy();
59
}
60
61
void COGLFragmentShaderCombiner::InitCombinerCycleFill(void)
62
{
63
COGLColorCombiner::InitCombinerCycleFill();
64
}
65
void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile)
66
{
67
COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile);
68
}
69
70
#ifdef DEBUGGER
71
void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void)
72
{
73
COGLColorCombiner::DisplaySimpleMuxString();
74
}
75
#endif
76
77
78
79
COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender)
80
: COGLColorCombiner4(pRender)
81
{
82
delete m_pDecodedMux;
83
m_pDecodedMux = new DecodedMuxForPixelShader;
84
m_bFragmentProgramIsSupported = false;
85
}
86
COGL_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
100
bool 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
116
void COGL_FragmentProgramCombiner::DisableCombiner(void)
117
{
118
glDisable(GL_FRAGMENT_PROGRAM_ARB);
119
OPENGL_CHECK_ERRORS;
120
COGLColorCombiner4::DisableCombiner();
121
}
122
123
void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void)
124
{
125
glDisable(GL_FRAGMENT_PROGRAM_ARB);
126
OPENGL_CHECK_ERRORS;
127
COGLColorCombiner4::InitCombinerCycleCopy();
128
}
129
130
void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void)
131
{
132
glDisable(GL_FRAGMENT_PROGRAM_ARB);
133
OPENGL_CHECK_ERRORS;
134
COGLColorCombiner4::InitCombinerCycleFill();
135
}
136
137
const 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
160
const 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
186
char oglNewFP[4092];
187
188
char* MuxToOC(uint8 val)
189
{
190
// For color channel
191
if( val&MUX_ALPHAREPLICATE )
192
return (char*)muxToFP_Maps[val&0x1F][1];
193
else
194
return (char*)muxToFP_Maps[val&0x1F][0];
195
}
196
197
char* MuxToOA(uint8 val)
198
{
199
// For alpha channel
200
return (char*)muxToFP_Maps[val&0x1F][0];
201
}
202
203
static 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
212
void 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
304
int 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
351
void 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
360
void 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
387
int 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
//////////////////////////////////////////////////////////////////////////
409
void 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
470
void 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
488
489