1 /*
2 Copyright (C) 2002 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 #include <stdint.h>
19 #include <algorithm>
20
21 #include <retro_miscellaneous.h>
22
23 #include "Combiner.h"
24 #include "Config.h"
25 #include "RenderBase.h"
26
27 #include "../../Graphics/image_convert.h"
28
29 #define ALLOW_USE_TEXTURE_FOR_CONSTANTS
30
31 static const uint8_t sc_Mux32[32] =
32 {
33 MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,
34 MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBINED|MUX_ALPHAREPLICATE,
35 MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE,
36 MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_K5, // Actually k5
37 MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,
38 MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,
39 MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,
40 MUX_UNK, MUX_UNK, MUX_UNK, MUX_0
41 };
42
43 static const uint8_t sc_Mux16[16] =
44 {
45 MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,
46 MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBALPHA,
47 MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE,
48 MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_0
49 };
50 static const uint8_t sc_Mux8[8] =
51 {
52 MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,
53 MUX_SHADE, MUX_ENV, MUX_1, MUX_0
54 };
55
56
57 const char * translatedCombTypes[] =
58 {
59 "0",
60 "1",
61 "COMBINED",
62 "TEXEL0",
63 "TEXEL1",
64 "PRIM",
65 "SHADE",
66 "ENV",
67 "COMBALPHA",
68 "T0_ALPHA_wrong",
69 "T1_ALPHA_wrong",
70 "PRIM_ALPHA_wrong",
71 "SHADE_ALPHA_wrong",
72 "ENV_ALPHA_wrong",
73 "LODFRAC",
74 "PRIMLODFRAC",
75 "K5",
76 "UNK",
77 "FACTOR_PRIM_MINUS_ENV",
78 "FACTOR_ENV_MINUS_PRIM",
79 "FACTOR_1_MINUS_PRIM",
80 "FACTOR_0_MINUS_PRIM",
81 "FACTOR_1_MINUS_ENV",
82 "FACTOR_0_MINUS_ENV",
83 "FACTOR_1_MINUS_PRIMALPHA",
84 "FACTOR_1_MINUS_ENVALPHA",
85 "FACTOR_HALF",
86 "PRIM_X_PRIMALPHA",
87 "1_MINUS_PRIM_X_ENV_PLUS_PRIM",
88 "ENV_X_PRIM",
89 "PRIM_X_1_MINUS_ENV",
90 "PRIM_X_PRIM",
91 "ENV_X_ENV",
92 };
93
94 const char* muxTypeStrs[] = {
95 "CM_FMT_TYPE_NOT_USED",
96 "CM_FMT_TYPE1_D",
97 "CM_FMT_TYPE2_A_ADD_D",
98 "CM_FMT_TYPE3_A_MOD_C",
99 "CM_FMT_TYPE4_A_SUB_B",
100 "CM_FMT_TYPE5_A_MOD_C_ADD_D",
101 "CM_FMT_TYPE6_A_LERP_B_C",
102 "CM_FMT_TYPE7_A_SUB_B_ADD_D",
103 "CM_FMT_TYPE8_A_SUB_B_MOD_C",
104 "CM_FMT_TYPE9_A_B_C_D",
105 "CM_FMT_TYPE_NOT_CHECKED",
106 };
107
Decode(uint32_t dwMux0,uint32_t dwMux1)108 void DecodedMux::Decode(uint32_t dwMux0, uint32_t dwMux1)
109 {
110 m_dwMux0 = dwMux0;
111 m_dwMux1 = dwMux1;
112
113 aRGB0 = uint8_t((dwMux0>>20)&0x0F); // c1 c1 // a0
114 bRGB0 = uint8_t((dwMux1>>28)&0x0F); // c1 c2 // b0
115 cRGB0 = uint8_t((dwMux0>>15)&0x1F); // c1 c3 // c0
116 dRGB0 = uint8_t((dwMux1>>15)&0x07); // c1 c4 // d0
117
118 aA0 = uint8_t((dwMux0>>12)&0x07); // c1 a1 // Aa0
119 bA0 = uint8_t((dwMux1>>12)&0x07); // c1 a2 // Ab0
120 cA0 = uint8_t((dwMux0>>9 )&0x07); // c1 a3 // Ac0
121 dA0 = uint8_t((dwMux1>>9 )&0x07); // c1 a4 // Ad0
122
123 aRGB1 = uint8_t((dwMux0>>5 )&0x0F); // c2 c1 // a1
124 bRGB1 = uint8_t((dwMux1>>24)&0x0F); // c2 c2 // b1
125 cRGB1 = uint8_t((dwMux0 )&0x1F); // c2 c3 // c1
126 dRGB1 = uint8_t((dwMux1>>6 )&0x07); // c2 c4 // d1
127
128 aA1 = uint8_t((dwMux1>>21)&0x07); // c2 a1 // Aa1
129 bA1 = uint8_t((dwMux1>>3 )&0x07); // c2 a2 // Ab1
130 cA1 = uint8_t((dwMux1>>18)&0x07); // c2 a3 // Ac1
131 dA1 = uint8_t((dwMux1 )&0x07); // c2 a4 // Ad1
132
133 //This function will translate the decode mux info further, so we can use
134 //the decode data better.
135 //Will translate A,B,C,D to unified presentation
136 aRGB0 = sc_Mux16[aRGB0];
137 bRGB0 = sc_Mux16[bRGB0];
138 cRGB0 = sc_Mux32[cRGB0];
139 dRGB0 = sc_Mux8[dRGB0];
140
141 aA0 = sc_Mux8[aA0];
142 bA0 = sc_Mux8[bA0];
143 cA0 = sc_Mux8[cA0];
144 dA0 = sc_Mux8[dA0];
145
146 aRGB1 = sc_Mux16[aRGB1];
147 bRGB1 = sc_Mux16[bRGB1];
148 cRGB1 = sc_Mux32[cRGB1];
149 dRGB1 = sc_Mux8[dRGB1];
150
151 aA1 = sc_Mux8[aA1];
152 bA1 = sc_Mux8[bA1];
153 cA1 = sc_Mux8[cA1];
154 dA1 = sc_Mux8[dA1];
155
156 m_bShadeIsUsed[1] = IsUsedInAlphaChannel(MUX_SHADE, MUX_MASK);
157 m_bShadeIsUsed[0] = IsUsedInColorChannel(MUX_SHADE, MUX_MASK);
158 m_bTexel0IsUsed = IsUsed(MUX_TEXEL0, MUX_MASK);
159 m_bTexel1IsUsed = IsUsed(MUX_TEXEL1, MUX_MASK);
160
161 m_dwShadeColorChannelFlag = 0;
162 m_dwShadeAlphaChannelFlag = 0;
163 m_ColorTextureFlag[0] = 0;
164 m_ColorTextureFlag[1] = 0;
165 }
166
Count(uint8_t val,int cycle,uint8_t mask)167 int DecodedMux::Count(uint8_t val, int cycle, uint8_t mask)
168 {
169 uint8_t* pmux = m_bytes;
170 int count=0;
171 int start=0;
172 int end=16;
173
174 if( cycle >= 0 )
175 {
176 start = cycle*4;
177 end = start+4;
178 }
179
180
181 for( int i=start; i<end; i++ )
182 {
183 if( (pmux[i]&mask) == (val&mask) )
184 {
185 count++;
186 }
187 }
188
189 return count;
190 }
191
192
IsUsed(uint8_t val,uint8_t mask)193 bool DecodedMux::IsUsed(uint8_t val, uint8_t mask)
194 {
195 uint8_t* pmux = m_bytes;
196 bool isUsed = false;
197 for( int i=0; i<16; i++ )
198 {
199 if( (pmux[i]&mask) == (val&mask) )
200 {
201 isUsed = true;
202 break;
203 }
204 }
205
206 return isUsed;
207 }
208
IsUsedInAlphaChannel(uint8_t val,uint8_t mask)209 bool DecodedMux::IsUsedInAlphaChannel(uint8_t val, uint8_t mask)
210 {
211 uint8_t* pmux = m_bytes;
212 bool isUsed = false;
213 for (int i=0; i<16; i++)
214 {
215 if ((i/4)%2 == 0)
216 continue; //Don't test color channel
217
218 if ((pmux[i] & mask) == (val & mask))
219 {
220 isUsed = true;
221 break;
222 }
223 }
224
225 return isUsed;
226 }
227
IsUsedInColorChannel(uint8_t val,uint8_t mask)228 bool DecodedMux::IsUsedInColorChannel(uint8_t val, uint8_t mask)
229 {
230 uint8_t* pmux = m_bytes;
231 bool isUsed = false;
232 for (int i=0; i<16; i++)
233 {
234 if ((i/4)%2 == 0 && (pmux[i]&mask) == (val&mask))
235 {
236 isUsed = true;
237 break;
238 }
239 }
240
241 return isUsed;
242 }
243
244
IsUsedInCycle(uint8_t val,int cycle,CombineChannel channel,uint8_t mask)245 bool DecodedMux::IsUsedInCycle(uint8_t val, int cycle, CombineChannel channel, uint8_t mask)
246 {
247 cycle *=2;
248 if (channel == ALPHA_CHANNEL)
249 cycle++;
250
251 uint8_t* pmux = m_bytes;
252 for (int i=0; i<4; i++)
253 {
254 if ((pmux[i+cycle*4]&mask) == (val&mask))
255 {
256 return true;
257 }
258 }
259
260 return false;
261 }
262
IsUsedInCycle(uint8_t val,int cycle,uint8_t mask)263 bool DecodedMux::IsUsedInCycle(uint8_t val, int cycle, uint8_t mask)
264 {
265 return IsUsedInCycle(val, cycle/2, cycle%2?ALPHA_CHANNEL:COLOR_CHANNEL, mask);
266 }
267
268
ConvertComplements()269 void DecodedMux::ConvertComplements()
270 {
271 //For (A-B)*C+D, if A=1, then we can convert A-B to Ac-0
272 if( aRGB0 != MUX_1 && bRGB0 != MUX_0 )
273 {
274 aRGB0 = bRGB0|MUX_COMPLEMENT;
275 bRGB0 = MUX_0;
276 }
277 if( aRGB1 != MUX_1 && bRGB1 != MUX_0 )
278 {
279 aRGB1 = bRGB1|MUX_COMPLEMENT;
280 bRGB1 = MUX_0;
281 }
282 if( aA0 != MUX_1 && bA0 != MUX_0 )
283 {
284 aA0 = bA0|MUX_COMPLEMENT;
285 bA0 = MUX_0;
286 }
287 if( aA1 != MUX_1 && bA1 != MUX_0 )
288 {
289 aA1 = bA1|MUX_COMPLEMENT;
290 bA1 = MUX_0;
291 }
292 }
293
294
GetCombinerFormatType(uint32_t cycle)295 CombinerFormatType DecodedMux::GetCombinerFormatType(uint32_t cycle)
296 {
297 //Analyze the formula
298 /*
299 C=0 = D
300 A==B = D
301 B=0, C=1, D=0 = A
302 A=1, B=0, D=0 = C
303 C=1, B==D = A
304 A=1, C=1, D=0 = 1-B
305 D = 1 = 1
306 */
307 return CM_FMT_TYPE_D;
308 }
309
Simplify(void)310 void DecodedMuxForPixelShader::Simplify(void)
311 {
312 CheckCombineInCycle1();
313 //Reformat(true);
314
315 if( g_curRomInfo.bTexture1Hack )
316 {
317 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 2, MUX_MASK);
318 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 3, MUX_MASK);
319 }
320 splitType[0] = CM_FMT_TYPE_NOT_USED;
321 splitType[1] = CM_FMT_TYPE_NOT_USED;
322 splitType[2] = CM_FMT_TYPE_NOT_USED;
323 splitType[3] = CM_FMT_TYPE_NOT_USED;
324 mType = CM_FMT_TYPE_NOT_USED;
325
326 m_bTexel0IsUsed = IsUsed(MUX_TEXEL0, MUX_MASK);
327 m_bTexel1IsUsed = IsUsed(MUX_TEXEL1, MUX_MASK);
328 }
329
Reset(void)330 void DecodedMuxForSemiPixelShader::Reset(void)
331 {
332 Decode(m_dwMux0, m_dwMux1);
333 splitType[0] = CM_FMT_TYPE_NOT_CHECKED;
334 splitType[1] = CM_FMT_TYPE_NOT_CHECKED;
335 splitType[2] = CM_FMT_TYPE_NOT_CHECKED;
336 splitType[3] = CM_FMT_TYPE_NOT_CHECKED;
337
338 Hack();
339
340 gRSP.bProcessDiffuseColor = false;
341 gRSP.bProcessSpecularColor = false;
342
343 CheckCombineInCycle1();
344 if( g_curRomInfo.bTexture1Hack )
345 {
346 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 2, MUX_MASK);
347 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 3, MUX_MASK);
348 }
349
350 m_bTexel0IsUsed = IsUsed(MUX_TEXEL0, MUX_MASK);
351 m_bTexel1IsUsed = IsUsed(MUX_TEXEL1, MUX_MASK);
352 }
353
Simplify(void)354 void DecodedMuxForOGL14V2::Simplify(void)
355 {
356 CheckCombineInCycle1();
357 if (g_curRomInfo.bTexture1Hack)
358 {
359 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 2, MUX_MASK);
360 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 3, MUX_MASK);
361 }
362 Reformat(true);
363
364 UseTextureForConstant();
365 Reformat(true);
366
367 m_bTexel0IsUsed = IsUsed(MUX_TEXEL0, MUX_MASK);
368 m_bTexel1IsUsed = IsUsed(MUX_TEXEL1, MUX_MASK);
369 }
370
Simplify(void)371 void DecodedMux::Simplify(void)
372 {
373 CheckCombineInCycle1();
374
375 if (gRDP.otherMode.text_lod)
376 ConvertLODFracTo0();
377
378 if (g_curRomInfo.bTexture1Hack)
379 {
380 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 2, MUX_MASK);
381 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 3, MUX_MASK);
382 }
383 Reformat(true);
384
385 UseShadeForConstant();
386 Reformat(true);
387
388 if (m_dwShadeColorChannelFlag == MUX_0)
389 {
390 MergeShadeWithConstants();
391 Reformat(true);
392 }
393
394 #ifdef ALLOW_USE_TEXTURE_FOR_CONSTANTS
395 UseTextureForConstant();
396 for (int i=0; i<2; i++)
397 {
398 if (m_ColorTextureFlag[i] != 0)
399 {
400 if (m_dwShadeColorChannelFlag == m_ColorTextureFlag[i])
401 {
402 ReplaceVal(MUX_SHADE, MUX_TEXEL0+i, N64Cycle0RGB, MUX_MASK);
403 ReplaceVal(MUX_SHADE, MUX_TEXEL0+i, N64Cycle1RGB, MUX_MASK);
404 m_dwShadeColorChannelFlag = 0;
405 }
406 if (m_dwShadeAlphaChannelFlag == m_ColorTextureFlag[i])
407 {
408 ReplaceVal(MUX_SHADE, MUX_TEXEL0+i, N64Cycle0Alpha, MUX_MASK);
409 ReplaceVal(MUX_SHADE, MUX_TEXEL0+i, N64Cycle1Alpha, MUX_MASK);
410 ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE, (MUX_TEXEL0+i)|MUX_ALPHAREPLICATE, N64Cycle0RGB, MUX_MASK_WITH_ALPHA);
411 ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE, (MUX_TEXEL0+i)|MUX_ALPHAREPLICATE, N64Cycle1RGB, MUX_MASK_WITH_ALPHA);
412 m_dwShadeAlphaChannelFlag = 0;
413 }
414 }
415 }
416 Reformat(true);
417 #endif
418
419 m_bTexel0IsUsed = IsUsed(MUX_TEXEL0, MUX_MASK);
420 m_bTexel1IsUsed = IsUsed(MUX_TEXEL1, MUX_MASK);
421 }
422
Reformat(bool do_complement)423 void DecodedMux::Reformat(bool do_complement)
424 {
425 if( m_dWords[N64Cycle0RGB] == m_dWords[N64Cycle1RGB] )
426 {
427 aRGB1 = MUX_0;
428 bRGB1 = MUX_0;
429 cRGB1 = MUX_0;
430 dRGB1 = MUX_COMBINED;
431 splitType[N64Cycle1RGB] = CM_FMT_TYPE_NOT_USED;
432 }
433
434 if( m_dWords[N64Cycle0Alpha] == m_dWords[N64Cycle1Alpha] )
435 {
436 aA1 = MUX_0;
437 bA1 = MUX_0;
438 cA1 = MUX_0;
439 dA1 = MUX_COMBINED;
440 splitType[N64Cycle1Alpha] = CM_FMT_TYPE_NOT_USED;
441 }
442
443 for( int i=0; i<4; i++ )
444 {
445 if( splitType[i] == CM_FMT_TYPE_NOT_USED )
446 {
447 continue; //Skip this, it is not used
448 }
449
450 N64CombinerType &m = m_n64Combiners[i];
451 //if( m.a == MUX_0 || m.c == MUX_0 || m.a == m.b ) m.a = m.b = m.c = MUX_0;
452 if( m.c == MUX_0 || m.a == m.b ) m.a = m.b = m.c = MUX_0;
453 if( do_complement && (m.b == MUX_1 || m.d == MUX_1) ) m.a = m.b = m.c = MUX_0;
454 if( m.a == MUX_0 && m.b == m.d )
455 {
456 m.a = m.b;
457 m.b = m.d = 0;
458 //Hack for Mario Tennis
459 if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && m.c == MUX_TEXEL1 )
460 {
461 if( do_complement )
462 m.c = MUX_TEXEL0|MUX_COMPLEMENT;
463 else
464 {
465 m.a = m.c;
466 m.c = m.b;
467 m.b = m.a;
468 m.a = MUX_1;
469 }
470 }
471 //m.c ^= MUX_COMPLEMENT;
472 }
473
474 //Type 1 == D
475 //Analyze the formula
476 //Check Type 1
477 //D = 1 = D(=1)
478 //C=0 = D
479 //A==B = D
480 //B=0, C=1, D=0 = A
481 //C=1, B==D = A
482 //A=1, B=0, D=0 = C
483 //A=1, C=1, D=0 = 1-B
484
485 splitType[i] = CM_FMT_TYPE_NOT_CHECKED; //All Type 1 will be changed to = D
486 if( m.c == MUX_0 || m.a==m.b || ( do_complement && (m.d == MUX_1 || m.b==MUX_1)) )
487 {
488 splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
489 m.a = m.b = m.c = MUX_0;
490 if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
491 }
492 else if( (m.b == MUX_0 && m.c == MUX_1 && m.d == MUX_0 ) || ( m.c == MUX_1 && m.b==m.d ) )
493 {
494 splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
495 m.d = m.a;
496 m.a = m.b = m.c = MUX_0;
497 if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
498 }
499 else if( m.a == MUX_1 && m.b == MUX_0 && m.d == MUX_0 )
500 {
501 splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
502 m.d = m.c;
503 m.a = m.b = m.c = MUX_0;
504 if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
505 }
506 else if( m.a == MUX_1 && m.c == MUX_1 && m.d == MUX_0 && do_complement )
507 {
508 splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
509 m.d = m.b^MUX_COMPLEMENT;
510 m.a = m.b = m.c = MUX_0;
511 if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
512 }
513
514 if( splitType[i] == CM_FMT_TYPE_NOT_USED )
515 continue;
516
517 if( splitType[i] == CM_FMT_TYPE_D )
518 {
519 if( (i == N64Cycle0RGB || i == N64Cycle0Alpha) && splitType[i+2]!=CM_FMT_TYPE_NOT_USED ) //Cycle 1's Color or Alpha
520 {
521 uint8_t saveD = m.d;
522 for( int j=0; j<4; j++ )
523 {
524 if( (m_bytes[j+i*4+8]&MUX_MASK) == MUX_COMBINED )
525 {
526 m_bytes[j+i*4+8] = saveD|(m_bytes[j+i*4+8]&0xC0); //Replace cycle's CMB with D from cycle 1
527 }
528 }
529 m_dWords[i] = m_dWords[i+2];
530 splitType[i+2]=CM_FMT_TYPE_NOT_USED;
531 m_dWords[i+2] = 0x02000000;
532 i=i-1; // Throw the first cycle result away, use 2nd cycle for the 1st cycle
533 // and then redo the 1st cycle
534 continue;
535 }
536
537 if( (i==2 || i == 3) && (m.d&MUX_MASK) == MUX_COMBINED )
538 {
539 splitType[i] = CM_FMT_TYPE_NOT_USED;
540 }
541 continue;
542 }
543
544
545 //Type 2: A+D ' ADD
546 //B=0, C=1 = A+D
547 //A=1, B=0 = C+D
548 splitType[i] = CM_FMT_TYPE_A_ADD_D; //All Type 2 will be changed to = A+D
549 if( m.b == MUX_0 && m.c == MUX_1 )
550 {
551 if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swapbyte(&m.a, &m.d);
552 if( m.a == MUX_COMBINED ) swapbyte(&m.a, &m.d);
553 continue;
554 }
555
556 if( m.a == MUX_1 && m.b == MUX_0 )
557 {
558 m.a = m.c; //Change format A+D
559 m.c = MUX_1;
560 if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swapbyte(&m.a, &m.d);
561 continue;
562 }
563
564
565 //Type 3: A*C
566 //B=0, D=0 = A*C
567 //A=1, D=0 = (1-A)*C
568 splitType[i] = CM_FMT_TYPE_A_MOD_C; //A*C
569 if( m.b == MUX_0 && m.d == MUX_0 )
570 {
571 if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swapbyte(&m.a, &m.c);
572 if( m.a == MUX_COMBINED ) swapbyte(&m.a, &m.c);
573 continue;
574 }
575
576 if( m.a == MUX_1 && m.d == MUX_0 && do_complement )
577 {
578 m.a = m.b^MUX_COMPLEMENT;
579 m.b = MUX_0;
580 if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swapbyte(&m.a, &m.c);
581 if( m.a == MUX_COMBINED ) swapbyte(&m.a, &m.c);
582 continue;
583 }
584
585 //Type 4: A-B ' SUB
586 //C=1, D=0 = A-B
587 splitType[i] = CM_FMT_TYPE_A_SUB_B; //A-B
588 if( m.c == MUX_1 && m.d == MUX_0 )
589 {
590 continue;
591 }
592
593 //Type 5: A*C+D , ' MULTIPLYADD
594 //B=0 = A*C+D
595 //A=1 = (1-B) * C + D
596 splitType[i] = CM_FMT_TYPE_A_MOD_C_ADD_D;
597 if( m.b == MUX_0 )
598 {
599 if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swapbyte(&m.a, &m.c);
600 if( m.a == MUX_COMBINED ) swapbyte(&m.a, &m.c);
601 continue;
602 }
603
604 if( m.a == MUX_1 && m.b!=m.d && do_complement )
605 {
606 m.a = m.b^MUX_COMPLEMENT;
607 m.b = MUX_0;
608 if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swapbyte(&m.a, &m.c);
609 if( m.a == MUX_COMBINED ) swapbyte(&m.a, &m.c);
610 continue;
611 }
612
613 //Type 6: (A-B)*C+B Map to LERP, or BLENDALPHA
614 //D==B
615 splitType[i] = CM_FMT_TYPE_A_LERP_B_C;
616 if( m.b == m.d )
617 {
618 continue;
619 }
620
621
622 //Type 7: A-B+D
623 //C=1 = A-B+D
624 splitType[i] = CM_FMT_TYPE_A_SUB_B_ADD_D;
625 if( m.c == MUX_1 )
626 {
627 if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swapbyte(&m.a, &m.c);
628 continue;
629 }
630
631 //Type 8: (A-B)*C
632 splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;
633 if( m.d == MUX_0 )
634 {
635 continue;
636 }
637
638 if( m.c == m.d && do_complement ) // (A-B)*C+C ==> (A + B|C ) * C
639 {
640 m.d = MUX_0;
641 m.b |= MUX_COMPLEMENT;
642 continue;
643 }
644
645 if( m.a == m.d )
646 {
647 splitType[i] = CM_FMT_TYPE_A_B_C_A;
648 continue;
649 }
650
651 //Type 9: (A-B)*C+D
652 splitType[i] = CM_FMT_TYPE_A_B_C_D;
653 }
654
655 if ((splitType[0] == CM_FMT_TYPE_D && splitType[2]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 1 Color
656 (!IsUsedInCycle(MUX_COMBINED, 1, COLOR_CHANNEL, MUX_MASK) && !IsUsedInCycle(MUX_COMBINED, 1, ALPHA_CHANNEL, MUX_MASK) && splitType[2]!= CM_FMT_TYPE_NOT_USED))
657 {
658 //Replace cycle 1 color with cycle 2 color because we have already replace cycle2's cmb
659 aRGB0 = aRGB1;
660 bRGB0 = bRGB1;
661 cRGB0 = cRGB1;
662 dRGB0 = dRGB1;
663 aRGB1 = MUX_0;
664 bRGB1 = MUX_0;
665 cRGB1 = MUX_0;
666 dRGB1 = MUX_COMBINED;
667 splitType[0] = splitType[2];
668 splitType[2] = CM_FMT_TYPE_NOT_USED;
669 }
670
671 if ((splitType[1] == CM_FMT_TYPE_D && splitType[3]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 2 Alpha
672 (!IsUsedInCycle(MUX_COMBINED, 1, ALPHA_CHANNEL, MUX_MASK) && !IsUsedInCycle(MUX_COMBINED|MUX_ALPHAREPLICATE, 1, COLOR_CHANNEL, MUX_MASK_WITH_ALPHA) && splitType[3]!= CM_FMT_TYPE_NOT_USED))
673 {
674 //Replace cycle 1 alpha with cycle 2 alpha because we have already replace cycle2's cmb
675 aA0 = aA1;
676 bA0 = bA1;
677 cA0 = cA1;
678 dA0 = dA1;
679 aA1 = MUX_0;
680 bA1 = MUX_0;
681 cA1 = MUX_0;
682 dA1 = MUX_COMBINED;
683 splitType[1] = splitType[3];
684 splitType[3] = CM_FMT_TYPE_NOT_USED;
685 }
686
687 if( splitType[0] == CM_FMT_TYPE_A_MOD_C && splitType[2] == CM_FMT_TYPE_A_ADD_D )
688 {
689 m_n64Combiners[0].d = (m_n64Combiners[2].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[2].d : m_n64Combiners[2].a;
690 splitType[0] = CM_FMT_TYPE_A_MOD_C_ADD_D;
691 splitType[2] = CM_FMT_TYPE_NOT_USED;
692 m_n64Combiners[2].a = MUX_0;
693 m_n64Combiners[2].c = MUX_0;
694 m_n64Combiners[2].d = MUX_COMBINED;
695 }
696
697 if( splitType[1] == CM_FMT_TYPE_A_MOD_C && splitType[3] == CM_FMT_TYPE_A_ADD_D )
698 {
699 m_n64Combiners[1].d = (m_n64Combiners[3].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[3].d : m_n64Combiners[3].a;
700 splitType[1] = CM_FMT_TYPE_A_MOD_C_ADD_D;
701 splitType[3] = CM_FMT_TYPE_NOT_USED;
702 m_n64Combiners[3].a = MUX_0;
703 m_n64Combiners[3].c = MUX_0;
704 m_n64Combiners[3].d = MUX_COMBINED;
705 }
706
707 signed cond3 = MAX(splitType[0], splitType[1]);
708 signed cond2 = MAX(cond3, splitType[2]);
709 mType = (CombinerFormatType)MAX(cond2,splitType[3]);
710 }
711
712 const char* MuxGroupStr[4] =
713 {
714 "Color0",
715 "Alpha0",
716 "Color1",
717 "Alpha1",
718 };
719
FormatStr(uint8_t val,char * buf)720 char* DecodedMux::FormatStr(uint8_t val, char *buf)
721 {
722 if( val == CM_IGNORE_BYTE )
723 {
724 strcpy(buf," ");
725 }
726 else
727 {
728 strcpy(buf, translatedCombTypes[val&MUX_MASK]);
729 if( val&MUX_ALPHAREPLICATE )
730 strcat(buf,"|A");
731 if( val&MUX_COMPLEMENT )
732 strcat(buf,"|C");
733 if( val&MUX_NEG )
734 strcat(buf,"|N");
735 }
736
737 return buf;
738 }
739
Display(bool simplified,FILE * fp)740 void DecodedMux::Display(bool simplified, FILE *fp)
741 {
742 DecodedMux decodedMux;
743 DecodedMux *mux;
744 if (simplified)
745 {
746 mux = this;
747 }
748 else
749 {
750 decodedMux.Decode(m_dwMux0, m_dwMux1);
751 mux = &decodedMux;
752 }
753
754 char buf0[30];
755 char buf1[30];
756 char buf2[30];
757 char buf3[30];
758
759 for (int i=0; i<2; i++)
760 {
761 for (int j=0; j<2; j++)
762 {
763 N64CombinerType &m = mux->m_n64Combiners[i+2*j];
764 if (fp != NULL)
765 {
766 fprintf(fp,"%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0),
767 FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3));
768 }
769 else
770 {
771 DebuggerAppendMsg("%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0),
772 FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3));
773 }
774 }
775 }
776 }
777
HowManyConstFactors()778 int DecodedMux::HowManyConstFactors()
779 {
780 int n = 0;
781
782 if (IsUsed(MUX_PRIM, MUX_MASK))
783 n++;
784
785 if (IsUsed(MUX_ENV, MUX_MASK))
786 n++;
787
788 if (IsUsed(MUX_LODFRAC, MUX_MASK))
789 n++;
790
791 if (IsUsed(MUX_PRIMLODFRAC, MUX_MASK))
792 n++;
793
794 return n;
795 }
796
HowManyTextures()797 int DecodedMux::HowManyTextures()
798 {
799 int n = 0;
800
801 if (IsUsed(MUX_TEXEL0, MUX_MASK))
802 n++;
803
804 if (IsUsed(MUX_TEXEL1, MUX_MASK))
805 n++;
806
807 return n;
808 }
809
CountTexels(void)810 int DecodedMux::CountTexels(void)
811 {
812 int count=0;
813
814 for (int i=0; i<4; i++)
815 {
816 N64CombinerType &m = m_n64Combiners[i];
817 count = MAX(count, ::CountTexel1Cycle(m));
818 if (count == 2)
819 break;
820 }
821
822 return count;
823 }
824
ReplaceVal(uint8_t val1,uint8_t val2,int cycle,uint8_t mask)825 void DecodedMux::ReplaceVal(uint8_t val1, uint8_t val2, int cycle, uint8_t mask)
826 {
827 int start = 0;
828 int end = 16;
829
830 if (cycle >= 0)
831 {
832 start = cycle*4;
833 end = start+4;
834 }
835
836 uint8_t* pmux = m_bytes;
837 for (int i=start; i<end; i++)
838 {
839 if ((pmux[i]&mask) == (val1&mask))
840 {
841 pmux[i] &= (~mask);
842 pmux[i] |= val2;
843 }
844 }
845 }
846
GetCycle(int cycle,CombineChannel channel)847 uint32_t DecodedMux::GetCycle(int cycle, CombineChannel channel)
848 {
849 uint32_t* pmux = m_dWords;
850 if (channel == COLOR_CHANNEL)
851 {
852 return pmux[cycle*2];
853 }
854 else
855 {
856 return pmux[cycle*2+1];
857 }
858
859 }
860
GetCycle(int cycle)861 uint32_t DecodedMux::GetCycle(int cycle)
862 {
863 return m_dWords[cycle];
864 }
865
866 enum ShadeConstMergeType
867 {
868 SHADE_DO_NOTHING,
869 SHADE_ADD_PRIM, // Shade+PRIM
870 SHADE_ADD_ENV, // Shade+ENV
871 SHADE_ADD_PRIM_ALPHA, // Shade+PRIM_ALPHA
872 SHADE_ADD_ENV_ALPHA, // Shade+ENV_ALPHA
873 SHADE_MINUS_PRIM_PLUS_ENV,
874 SHADE_MINUS_ENV_PLUS_PRIM,
875 SHADE_MOD_ENV,
876 };
877
878 typedef struct
879 {
880 uint64_t mux; // simplified
881 ShadeConstMergeType op;
882 } ShadeConstMergeMapType;
883
884 ShadeConstMergeMapType MergeShadeWithConstantsMaps[] =
885 {
886 {0, SHADE_DO_NOTHING},
887 {0x0007000600070006LL, SHADE_MOD_ENV}, // SHADE * ENV
888 };
889
890 // 0x05070501, 0x00070006 //(1 - PRIM) * ENV + PRIM
891 // 0x00050003, 0x00050003 //(TEXEL0 - 0) * PRIM + 0
892
MergeShadeWithConstants(void)893 void DecodedMux::MergeShadeWithConstants(void)
894 {
895 // This function should be called after the mux has been simplified
896 // The goal of this function is to merge as many as possible constants with shade
897 // so to reduce the totally number of constants to 0 or 1
898 // And at the same time, to reduce the complexity of the whole mux
899 // so we can implement the mux easier when lower end video cards
900
901 // We can only try to merge shade with constants for:
902 // 1 cycle mode or 2 cycle mode and shade is not used in the 2nd cycle
903
904 if (m_bShadeIsUsed[0]) MergeShadeWithConstantsInChannel(COLOR_CHANNEL);
905 if (m_bShadeIsUsed[1]) MergeShadeWithConstantsInChannel(ALPHA_CHANNEL);
906 }
907
MergeShadeWithConstantsInChannel(CombineChannel channel)908 void DecodedMux::MergeShadeWithConstantsInChannel(CombineChannel channel)
909 {
910 bool usedIn[2];
911 uint32_t cycleVal;
912 int cycleNum;
913
914 usedIn[0] = IsUsedInCycle(MUX_SHADE, channel, MUX_MASK);
915 usedIn[1] = IsUsedInCycle(MUX_SHADE, channel+2, MUX_MASK);
916 if( usedIn[0] && usedIn[1] && GetCycle(channel)!=GetCycle(channel+2) )
917 {
918 //Shade is used in more than 1 cycles, and the ways it is used are different
919 //in cycles, so we can not merge shade with const factors
920 return;
921 }
922
923 if( usedIn[0] )
924 {
925 cycleVal = GetCycle(channel);
926 cycleNum = 0;
927 }
928 else
929 {
930 cycleVal = GetCycle(channel+2);
931 cycleNum = 1;
932 }
933
934
935 //Update to here, Shade is either used only in 1 cycle, or the way it is used are totally
936 //the same in different cycles
937
938 if (cycleVal == 0x06000000 || IsUsedInCycle(MUX_COMBINED, channel+cycleNum*2, MUX_MASK)) // (0-0)*0+Shade
939 {
940 return;
941 }
942
943 //Now we can merge shade with consts
944 for( int i=0; i<2; i++ )
945 {
946 if( usedIn[i] )
947 {
948 N64CombinerType &m = m_n64Combiners[channel+i*2];
949 if (IsUsedInCycle(MUX_TEXEL0, i*2+channel, MUX_MASK) || IsUsedInCycle(MUX_TEXEL1, i*2+channel, MUX_MASK))
950 {
951 if( (m.a&MUX_MASK) == MUX_TEXEL0 || (m.a&MUX_MASK) == MUX_TEXEL1 )
952 {
953 // m.a is texel, can not merge constant with shade
954 return;
955 }
956 else if( (m.b&MUX_MASK) == MUX_TEXEL0 || (m.b&MUX_MASK) == MUX_TEXEL1 )
957 {
958 // m.b is texel, can not merge constant with shade
959 return;
960 }
961 else if(( (m.c&MUX_MASK) == MUX_TEXEL0 || (m.c&MUX_MASK) == MUX_TEXEL1 ) )
962 {
963 if( (m.d&MUX_MASK) != MUX_SHADE )
964 {
965 cycleVal &= 0x0000FFFF; // A-B
966 }
967 else if( (m.a&MUX_MASK) == MUX_SHADE || (m.b&MUX_MASK) == MUX_SHADE )
968 {
969 return;
970 }
971 }
972 else if( (m.d&MUX_MASK) == MUX_TEXEL0 || (m.d&MUX_MASK) == MUX_TEXEL1 )
973 {
974 cycleVal &= 0x00FFFFFF; // (A-B)*C
975 }
976 }
977 else
978 {
979 m.a = m.b = m.c = MUX_0;
980 m.d = MUX_SHADE;
981 splitType[i*2+channel] = CM_FMT_TYPE_D;
982 }
983 }
984 }
985
986 if (channel == COLOR_CHANNEL)
987 m_dwShadeColorChannelFlag = cycleVal;
988 else
989 m_dwShadeAlphaChannelFlag = cycleVal;
990 }
991
992
MergeConstants(void)993 void DecodedMux::MergeConstants(void)
994 {
995 // This function should be called afte the mux has been simplified
996 // The goal of this function is to merge remain constants and to reduce the
997 // total number of constants, so we can implement the mux easiler
998
999 // This function should be called after the MergeShadeWithConstants() function
1000 }
1001
1002
UseShadeForConstant(void)1003 void DecodedMux::UseShadeForConstant(void)
1004 {
1005 // If shade is not used in the mux, we can use it for constants
1006 // This function should be called after constants have been merged
1007
1008 bool doAlphaChannel = true;
1009 uint8_t mask = (uint8_t)~MUX_COMPLEMENT;
1010
1011 int constants = 0;
1012 if (IsUsed(MUX_ENV, MUX_MASK)) constants++;
1013 if (IsUsed(MUX_PRIM, MUX_MASK)) constants++;
1014 if (IsUsed(MUX_LODFRAC, MUX_MASK)) constants++;
1015 if (IsUsed(MUX_PRIMLODFRAC, MUX_MASK)) constants++;
1016
1017 bool forceToUsed = constants>m_maxConstants;
1018
1019 if (!IsUsedInColorChannel(MUX_SHADE, MUX_MASK) && (forceToUsed || MAX(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D))
1020 {
1021 int countEnv = Count(MUX_ENV, N64Cycle0RGB, mask) + Count(MUX_ENV, N64Cycle1RGB, mask);
1022 int countPrim = Count(MUX_PRIM, N64Cycle0RGB, mask) + Count(MUX_PRIM, N64Cycle1RGB, mask);
1023 if (countEnv+countPrim > 0)
1024 {
1025 if (countPrim >= countEnv)
1026 {
1027 //TRACE0("Use Shade for PRIM in color channel");
1028 ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0RGB, MUX_MASK);
1029 ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1RGB, MUX_MASK);
1030 m_dwShadeColorChannelFlag = MUX_PRIM;
1031 }
1032 else if (countEnv > 0)
1033 {
1034 //TRACE0("Use Shade for ENV in color channel");
1035 ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0RGB, MUX_MASK);
1036 ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1RGB, MUX_MASK);
1037 m_dwShadeColorChannelFlag = MUX_ENV;
1038 }
1039
1040 if (IsUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE, mask))
1041 {
1042 m_dwShadeAlphaChannelFlag = m_dwShadeColorChannelFlag;
1043 ReplaceVal((uint8_t)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle0Alpha, MUX_MASK);
1044 ReplaceVal((uint8_t)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle1Alpha, MUX_MASK);
1045 doAlphaChannel = false;
1046 }
1047 }
1048 }
1049
1050 if (doAlphaChannel && !IsUsedInAlphaChannel(MUX_SHADE, MUX_MASK) && !IsUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE, MUX_MASK_WITH_ALPHA))
1051 {
1052 int countEnv = Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1053 int countPrim = Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1054
1055 if (forceToUsed || MAX(splitType[1], splitType[3]) >= CM_FMT_TYPE_A_MOD_C_ADD_D ||
1056 (MAX(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D && countEnv+countPrim > 0 ))
1057 {
1058 countEnv = Count(MUX_ENV, N64Cycle0Alpha, MUX_MASK) +
1059 Count(MUX_ENV, N64Cycle1Alpha, MUX_MASK) +
1060 Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) +
1061 Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1062
1063 countPrim = Count(MUX_PRIM, N64Cycle0Alpha, MUX_MASK) +
1064 Count(MUX_PRIM, N64Cycle1Alpha, MUX_MASK) +
1065 Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) +
1066 Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1067
1068 if (countEnv+countPrim > 0)
1069 {
1070 if (countPrim > 0 && m_dwShadeColorChannelFlag == MUX_PRIM)
1071 {
1072 //TRACE0("Use Shade for PRIM in alpha channel");
1073 ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha, MUX_MASK);
1074 ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha, MUX_MASK);
1075 ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
1076 ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1077 m_dwShadeAlphaChannelFlag = MUX_PRIM;
1078 }
1079 else if (countEnv>0 && m_dwShadeColorChannelFlag == MUX_ENV)
1080 {
1081 //TRACE0("Use Shade for PRIM in alpha channel");
1082 ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha, MUX_MASK);
1083 ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha, MUX_MASK);
1084 ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
1085 ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1086 m_dwShadeAlphaChannelFlag = MUX_ENV;
1087 }
1088 else if (countPrim >= countEnv)
1089 {
1090 //TRACE0("Use Shade for PRIM in alpha channel");
1091 ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha, MUX_MASK);
1092 ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha, MUX_MASK);
1093 ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
1094 ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1095 m_dwShadeAlphaChannelFlag = MUX_PRIM;
1096 }
1097 else if (countEnv > 0)
1098 {
1099 //TRACE0("Use Shade for ENV in alpha channel");
1100 ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha, MUX_MASK);
1101 ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha, MUX_MASK);
1102 ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
1103 ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
1104 m_dwShadeAlphaChannelFlag = MUX_ENV;
1105 }
1106 }
1107 }
1108 }
1109 }
1110
UseTextureForConstant(void)1111 void DecodedMux::UseTextureForConstant(void)
1112 {
1113 int numofconst = HowManyConstFactors();
1114 int numOftex = HowManyTextures();
1115
1116 if (numofconst > m_maxConstants && numOftex < m_maxTextures)
1117 {
1118 // We can use a texture for a constant
1119 for (int i=0; i<2 && numofconst > m_maxConstants ; i++)
1120 {
1121 if (IsUsed(MUX_TEXEL0+i, MUX_MASK))
1122 {
1123 continue; // can not use this texture
1124 }
1125
1126 if (IsUsed(MUX_PRIM, MUX_MASK))
1127 {
1128 ReplaceVal(MUX_PRIM, MUX_TEXEL0+i, -1, MUX_MASK);
1129 m_ColorTextureFlag[i] = MUX_PRIM;
1130 numofconst--;
1131 continue;
1132 }
1133
1134 if (IsUsed(MUX_ENV, MUX_MASK))
1135 {
1136 ReplaceVal(MUX_ENV, MUX_TEXEL0+i, -1, MUX_MASK);
1137 m_ColorTextureFlag[i] = MUX_ENV;
1138 numofconst--;
1139 continue;
1140 }
1141
1142 if (IsUsed(MUX_LODFRAC, MUX_MASK))
1143 {
1144 ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i, -1, MUX_MASK);
1145 m_ColorTextureFlag[i] = MUX_LODFRAC;
1146 numofconst--;
1147 continue;
1148 }
1149
1150 if (IsUsed(MUX_PRIMLODFRAC, MUX_MASK))
1151 {
1152 ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i, -1, MUX_MASK);
1153 m_ColorTextureFlag[i] = MUX_PRIMLODFRAC;
1154 numofconst--;
1155 continue;
1156 }
1157 }
1158 }
1159 }
1160
1161
UseTextureForConstant(void)1162 void DecodedMuxForOGL14V2::UseTextureForConstant(void)
1163 {
1164 bool envused = IsUsed(MUX_ENV, MUX_MASK);
1165 bool lodused = IsUsed(MUX_LODFRAC, MUX_MASK);
1166
1167 int numofconst = 0;
1168 if (envused) numofconst++;
1169 if (lodused) numofconst++;
1170
1171 int numOftex = HowManyTextures();
1172
1173 if (numofconst > 0 && numOftex < 2)
1174 {
1175 // We can use a texture for a constant
1176 for (int i=0; i<2 && numofconst > 0 ; i++)
1177 {
1178 if (IsUsed(MUX_TEXEL0+i, MUX_MASK))
1179 {
1180 continue; // can not use this texture
1181 }
1182
1183 if (envused)
1184 {
1185 ReplaceVal(MUX_ENV, MUX_TEXEL0+i, -1, MUX_MASK);
1186 m_ColorTextureFlag[i] = MUX_ENV;
1187 numofconst--;
1188 envused = false;
1189 continue;
1190 }
1191
1192 if (IsUsed(MUX_LODFRAC, MUX_MASK))
1193 {
1194 ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i, -1, MUX_MASK);
1195 m_ColorTextureFlag[i] = MUX_LODFRAC;
1196 numofconst--;
1197 continue;
1198 }
1199
1200 if (IsUsed(MUX_PRIMLODFRAC, MUX_MASK))
1201 {
1202 ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i, -1, MUX_MASK);
1203 m_ColorTextureFlag[i] = MUX_PRIMLODFRAC;
1204 numofconst--;
1205 continue;
1206 }
1207 }
1208 }
1209 }
1210
1211 #ifdef DEBUGGER
1212 extern const char *translatedCombTypes[];
DisplayMuxString(const char * prompt)1213 void DecodedMux::DisplayMuxString(const char *prompt)
1214 {
1215 DebuggerAppendMsg("//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
1216 Display(false, NULL);
1217 TRACE0("\n");
1218 }
1219
DisplaySimpliedMuxString(const char * prompt)1220 void DecodedMux::DisplaySimpliedMuxString(const char *prompt)
1221 {
1222 DebuggerAppendMsg("//Simplified Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
1223 DebuggerAppendMsg("Simplified DWORDs=%08X, %08X, %08X, %08X", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]);
1224 Display(true, NULL);
1225 DebuggerAppendMsg("Simplified type: %s", muxTypeStrs[mType]);
1226 if( m_dwShadeColorChannelFlag != 0 )
1227 {
1228 if( m_dwShadeColorChannelFlag == MUX_ENV )
1229 TRACE0("Shade = ENV in color channel")
1230 else if( m_dwShadeColorChannelFlag == MUX_PRIM )
1231 TRACE0("Shade = PRIM in color channel")
1232 else if( m_dwShadeColorChannelFlag == MUX_LODFRAC )
1233 TRACE0("Shade = MUX_LODFRAC in color channel")
1234 else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC )
1235 TRACE0("Shade = MUX_PRIMLODFRAC in color channel")
1236 else
1237 DisplayConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL);
1238 }
1239 if( m_dwShadeAlphaChannelFlag != 0 )
1240 {
1241 if( m_dwShadeAlphaChannelFlag == MUX_ENV )
1242 TRACE0("Shade = ENV in alpha channel")
1243 else if( m_dwShadeAlphaChannelFlag == MUX_PRIM )
1244 TRACE0("Shade = PRIM in alpha channel")
1245 else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC )
1246 TRACE0("Shade = MUX_LODFRAC in alpha channel")
1247 else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC )
1248 TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel")
1249 else
1250 DisplayConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL);
1251 }
1252
1253 for( int i=0; i<2; i++ )
1254 {
1255 if( m_ColorTextureFlag[i] != 0 )
1256 {
1257 if( m_ColorTextureFlag[i] == MUX_ENV )
1258 TRACE1("Tex %d = ENV", i)
1259 else if( m_ColorTextureFlag[i] == MUX_PRIM )
1260 TRACE1("Tex %d = PRIM", i)
1261 else if( m_ColorTextureFlag[i] == MUX_LODFRAC )
1262 TRACE1("Tex %d = MUX_LODFRAC", i)
1263 else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC )
1264 TRACE1("Tex %d = MUX_PRIMLODFRAC", i)
1265 }
1266 }
1267
1268
1269 TRACE0("\n");
1270 }
1271
DisplayConstantsWithShade(uint32_t flag,CombineChannel channel)1272 void DecodedMux::DisplayConstantsWithShade(uint32_t flag,CombineChannel channel)
1273 {
1274 DebuggerAppendMsg("Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha");
1275 }
1276 #else
1277
1278 extern const char *translatedCombTypes[];
LogMuxString(const char * prompt,FILE * fp)1279 void DecodedMux::LogMuxString(const char *prompt, FILE *fp)
1280 {
1281 fprintf(fp, "//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
1282 Display(false, fp);
1283 TRACE0("\n");
1284 }
1285
LogSimpliedMuxString(const char * prompt,FILE * fp)1286 void DecodedMux::LogSimpliedMuxString(const char *prompt, FILE *fp)
1287 {
1288 fprintf(fp, "//Simplified Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
1289 fprintf(fp, "Simplified DWORDs=%08X, %08X, %08X, %08X\n", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]);
1290 Display(true, fp);
1291 fprintf(fp, "Simplified type: %s", muxTypeStrs[mType]);
1292 if( m_dwShadeColorChannelFlag != 0 )
1293 {
1294 if( m_dwShadeColorChannelFlag == MUX_ENV )
1295 TRACE0("Shade = ENV in color channel")
1296 else if( m_dwShadeColorChannelFlag == MUX_PRIM )
1297 TRACE0("Shade = PRIM in color channel")
1298 else if( m_dwShadeColorChannelFlag == MUX_LODFRAC )
1299 TRACE0("Shade = MUX_LODFRAC in color channel")
1300 else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC )
1301 TRACE0("Shade = MUX_PRIMLODFRAC in color channel")
1302 else
1303 LogConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL,fp);
1304 }
1305
1306 if( m_dwShadeAlphaChannelFlag != 0 )
1307 {
1308 if( m_dwShadeAlphaChannelFlag == MUX_ENV )
1309 TRACE0("Shade = ENV in alpha channel")
1310 else if( m_dwShadeAlphaChannelFlag == MUX_PRIM )
1311 TRACE0("Shade = PRIM in alpha channel")
1312 else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC )
1313 TRACE0("Shade = MUX_LODFRAC in alpha channel")
1314 else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC )
1315 TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel")
1316 else
1317 LogConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL,fp);
1318 }
1319
1320 for( int i=0; i<2; i++ )
1321 {
1322 if( m_ColorTextureFlag[i] != 0 )
1323 {
1324 if( m_ColorTextureFlag[i] == MUX_ENV )
1325 TRACE1("Tex %d = ENV", i)
1326 else if( m_ColorTextureFlag[i] == MUX_PRIM )
1327 TRACE1("Tex %d = PRIM", i)
1328 else if( m_ColorTextureFlag[i] == MUX_LODFRAC )
1329 TRACE1("Tex %d = MUX_LODFRAC", i)
1330 else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC )
1331 TRACE1("Tex %d = MUX_PRIMLODFRAC", i)
1332 }
1333 }
1334
1335 TRACE0("\n");
1336 }
1337
LogConstantsWithShade(uint32_t flag,CombineChannel channel,FILE * fp)1338 void DecodedMux::LogConstantsWithShade(uint32_t flag,CombineChannel channel, FILE *fp)
1339 {
1340 fprintf(fp, "Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha");
1341 }
1342 #endif
1343
1344
To_AB_Add_CD_Format(void)1345 void DecodedMux::To_AB_Add_CD_Format(void) // Use by TNT,Geforce
1346 {
1347 // This function should be called after calling reformat
1348 // This function will not be called by default, can be called optionally
1349 // by TNT/Geforce combiner compilers
1350
1351 for( int i=0; i<2; i++ )
1352 {
1353 N64CombinerType &m0 = m_n64Combiners[i];
1354 N64CombinerType &m1 = m_n64Combiners[i+2];
1355 switch( splitType[i] )
1356 {
1357 case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage
1358 if( splitType[i+2] == CM_FMT_TYPE_NOT_USED )
1359 {
1360 m1.a = m0.d;
1361 m1.d = MUX_COMBINED;
1362 splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
1363
1364 m0.d = MUX_0;
1365 splitType[i] = CM_FMT_TYPE_A_SUB_B;
1366 }
1367 else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C )
1368 {
1369 if( (m1.c&MUX_MASK) == MUX_COMBINED ) swapbyte(&m1.a, &m1.c);
1370 m1.b = m1.d = m1.c;
1371 m1.c = (m0.d | (m1.a & (~MUX_MASK)));
1372 splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD;
1373
1374 m0.d = MUX_0;
1375 splitType[i] = CM_FMT_TYPE_A_SUB_B;
1376 }
1377 break;
1378 case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage
1379 m0.d = m0.b;
1380 m0.b = m0.c;
1381 splitType[i] = CM_FMT_TYPE_AB_SUB_CD;
1382 break;
1383 case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage
1384 m0.d = m0.b;
1385 m0.b = m0.c;
1386 splitType[i] = CM_FMT_TYPE_AB_ADD_CD;
1387 break;
1388 case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D
1389 case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+D
1390 if( splitType[i+2] == CM_FMT_TYPE_NOT_USED )
1391 {
1392 m1.a = m0.d;
1393 m1.d = MUX_COMBINED;
1394 splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
1395
1396 m0.d = m0.b;
1397 m0.b = m0.c;
1398 splitType[i] = CM_FMT_TYPE_AB_SUB_CD;
1399 }
1400 else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C )
1401 {
1402 if( (m1.c&MUX_MASK) == MUX_COMBINED ) swapbyte(&m1.a, &m1.c);
1403 m1.b = m1.d = m1.c;
1404 m1.c = (m0.d | (m1.a & (~MUX_MASK)));
1405 splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD;
1406
1407 m0.d = m0.b;
1408 m0.b = m0.c;
1409 splitType[i] = CM_FMT_TYPE_AB_ADD_CD;
1410 }
1411 break;
1412 default:
1413 break;
1414 }
1415 }
1416 }
1417
To_AB_Add_C_Format(void)1418 void DecodedMux::To_AB_Add_C_Format(void) // Use by ATI Radeon
1419 {
1420 // This function should be called after calling reformat
1421 // This function will not be called by default, can be called optionally
1422 // by ATI combiner compilers
1423 }
1424
CheckCombineInCycle1(void)1425 void DecodedMux::CheckCombineInCycle1(void)
1426 {
1427 if (IsUsedInCycle(MUX_COMBINED, 0, COLOR_CHANNEL, MUX_MASK))
1428 ReplaceVal(MUX_COMBINED, MUX_SHADE, 0, MUX_MASK);
1429
1430 if (IsUsedInCycle(MUX_COMBALPHA, 0, COLOR_CHANNEL, MUX_MASK))
1431 ReplaceVal(MUX_COMBALPHA, MUX_SHADE|MUX_ALPHAREPLICATE, 0, MUX_MASK);
1432
1433 if (IsUsedInCycle(MUX_COMBINED, 0, ALPHA_CHANNEL, MUX_MASK))
1434 {
1435 if (cA0 == MUX_COMBINED && cRGB0 == MUX_LODFRAC && bRGB0 == dRGB0 && bA0 == dA0)
1436 cA0 = MUX_LODFRAC;
1437 else
1438 ReplaceVal(MUX_COMBINED, MUX_SHADE, 1, MUX_MASK);
1439 }
1440
1441 if (IsUsedInCycle(MUX_COMBALPHA, 0, ALPHA_CHANNEL, MUX_MASK))
1442 ReplaceVal(MUX_COMBALPHA, MUX_SHADE, 1, MUX_MASK);
1443 }
1444
SplitComplexStages()1445 void DecodedMux::SplitComplexStages()
1446 {
1447 for( int i=0; i<2; i++) // Color channel and alpha channel
1448 {
1449 if( splitType[i+2] != CM_FMT_TYPE_NOT_USED )
1450 continue;
1451
1452 N64CombinerType &m = m_n64Combiners[i];
1453 N64CombinerType &m2 = m_n64Combiners[i+2];
1454
1455 switch( splitType[i] )
1456 {
1457 case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D can mapped to MULTIPLYADD(arg1,arg2,arg0)
1458 m2.a = m.d;
1459 m2.d = MUX_COMBINED;
1460 m2.c = MUX_1;
1461 m2.b = 0;
1462 splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
1463 m.d = MUX_0;
1464 splitType[i] = CM_FMT_TYPE_A_MOD_C;
1465 break;
1466 case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage
1467 m2.a = m.d;
1468 m2.d = MUX_COMBINED;
1469 m2.c = MUX_1;
1470 m2.b=0;
1471 splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
1472 m.d = MUX_0;
1473 splitType[i] = CM_FMT_TYPE_A_SUB_B;
1474 break;
1475 case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage
1476 m2.a = m.c;
1477 m2.c = MUX_COMBINED;
1478 m2.d = m2.b=0;
1479 splitType[i+2] = CM_FMT_TYPE_A_MOD_C;
1480 m.c = MUX_1;
1481 splitType[i] = CM_FMT_TYPE_A_SUB_B;
1482 break;
1483 case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage
1484 m2.a = m.c;
1485 m2.c = MUX_COMBINED;
1486 m2.d = m2.b = 0;
1487 splitType[i+2] = CM_FMT_TYPE_A_MOD_C;
1488 m.c = MUX_1;
1489 m.d = m.b;
1490 m.b = MUX_0;
1491 splitType[i] = CM_FMT_TYPE_A_ADD_D;
1492 break;
1493 case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D can not map very well in 1 stage
1494 m2.a = m.d;
1495 m2.d = MUX_COMBINED;
1496 m2.c = MUX_1;
1497 m2.b = 0;
1498 splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
1499 m.d = MUX_0;
1500 splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;
1501 break;
1502 case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+A can not map very well in 1 stage
1503 m2.a = m.d;
1504 m2.d = MUX_COMBINED;
1505 m2.c = MUX_1;
1506 m2.b = 0;
1507 splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
1508 m.d = MUX_0;
1509 splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;
1510 break;
1511 default:
1512 break;
1513 }
1514 }
1515 //Reformat(true);
1516 //UseShadeForConstant();
1517 }
1518
1519
ConvertLODFracTo0()1520 void DecodedMux::ConvertLODFracTo0()
1521 {
1522 ReplaceVal(MUX_LODFRAC, MUX_0, -1, MUX_MASK);
1523 ReplaceVal(MUX_PRIMLODFRAC, MUX_0, -1, MUX_MASK);
1524 }
1525
1526
Hack(void)1527 void DecodedMux::Hack(void)
1528 {
1529 if( options.enableHackForGames == HACK_FOR_TONYHAWK )
1530 {
1531 if( gRSP.curTile == 1 )
1532 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, -1, MUX_MASK);
1533 }
1534 else if( options.enableHackForGames == HACK_FOR_ZELDA || options.enableHackForGames == HACK_FOR_ZELDA_MM)
1535 {
1536 if( m_dwMux1 == 0xfffd9238 && m_dwMux0 == 0x00ffadff )
1537 ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, -1, MUX_MASK);
1538 else if( m_dwMux1 == 0xff5bfff8 && m_dwMux0 == 0x00121603 )
1539 {
1540 // The Zelda road trace
1541 ReplaceVal(MUX_TEXEL1, MUX_0, -1, MUX_MASK);
1542 }
1543 }
1544 else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS )
1545 {
1546 if( m_dwMux1 == 0xffebdbc0 && m_dwMux0 == 0x00ffb9ff )
1547 {
1548 // Player shadow
1549 //m_decodedMux.dRGB0 = MUX_TEXEL0;
1550 //m_decodedMux.dRGB1 = MUX_COMBINED;
1551 cA1 = MUX_TEXEL0;
1552 }
1553 }
1554 else if( options.enableHackForGames == HACK_FOR_MARIO_GOLF )
1555 {
1556 // Hack for Mario Golf
1557 if( m_dwMux1 == 0xf1ffca7e || m_dwMux0 == 0x00115407 )
1558 {
1559 // The grass
1560 ReplaceVal(MUX_TEXEL0, MUX_TEXEL1, -1, MUX_MASK);
1561 }
1562 }
1563 else if( options.enableHackForGames == HACK_FOR_TOPGEARRALLY )
1564 {
1565 //Mux=0x00317e025ffef3fa Used in TOP GEAR RALLY
1566 //Color0: (PRIM - ENV) * TEXEL1 + ENV
1567 //Color1: (COMBINED - 0) * TEXEL1 + 0
1568 //Alpha0: (0 - 0) * 0 + TEXEL0
1569 //Alpha1: (0 - 0) * 0 + TEXEL1
1570 if( m_dwMux1 == 0x5ffef3fa || m_dwMux0 == 0x00317e02 )
1571 {
1572 // The grass
1573 //ReplaceVal(MUX_TEXEL0, MUX_TEXEL1, -1, MUX_MASK);
1574 dA1 = MUX_COMBINED;
1575 //aA1 = MUX_COMBINED;
1576 //cA1 = MUX_TEXEL1;
1577 //dA1 = MUX_0;
1578 cRGB1 = MUX_TEXEL0;
1579 }
1580 }
1581 }
1582
1583